Skip to content

Commit 2e48dd9

Browse files
committed
Mostly finished new markdown README and nlp bugfixes
1 parent 21a9117 commit 2e48dd9

File tree

3 files changed

+176
-42
lines changed

3 files changed

+176
-42
lines changed

README.md

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# W.I.L.L
2+
3+
W.I.L.L is a Python based, event and plugin driven personal assistant.
4+
5+
- Smart, efficient, spacy driven multithreaded nlp
6+
- A full, event driven plugin framework supporting multiple types of plugins with room for expansion
7+
- Can be used with a variety of different clients
8+
9+
Plugins:
10+
- Can be written in Python or Json (more coming!)
11+
- Are activiated on W.I.L.L initiation or shutdown
12+
- Are activated based on entity recognition, POS tags, keywords, or even the presence of questions
13+
- Can interactively communicate with the user without having to re-run parsing every time
14+
15+
16+
W.I.L.L started as my personal project but now has an active community of users and contributers. If you want to contribute by adding plugins, or even editing the framework, just submit a pull reuqest! Working plugins that are legal, useful, and original will always be accepted. .
17+
18+
### Version
19+
3.0.1
20+
21+
### Tech
22+
23+
W.I.L.L is open source with a [public repository][will]
24+
on GitHub.
25+
26+
### Installation
27+
28+
W.I.L.L is available via pip, but first some things must be obtained
29+
30+
To run the search module, you need a wolframalpha API key. Get one from http://products.wolframalpha.com/api/
31+
32+
### Plugins
33+
34+
The following plugins are currently available for W.I.L.L, with many more on the way.
35+
36+
Finished:
37+
* Open (Use xdg-open, start, or open to open any program or file on the operating system)
38+
* Search (Use Google, Wolframalpha, and Wikipedia to find an answer to most questions)
39+
* Execute (Execute a terminal command)
40+
41+
In development:
42+
* Chromecast (Uses pychromecast and splinter to cast several popular streaming services)
43+
* Spotify (Access Spotify premium API)
44+
45+
### Plugin Creation
46+
47+
Writing a plugin for W.I.L.L is easier than you might think. Currently, W.I.L.L supports two types of plugins. Json and Python. All plugins should go in W.I.L.L/plugins.
48+
49+
Special thanks to https://github.com/brenttaylor for his contributions to the plugin framework
50+
51+
#### Python
52+
The way W.I.L.L is designed, you can plug in pretty much any python file that you've made, just by adding a decorator.
53+
Let's write a plugin. First, you need to import the API that W.I.L.L uses. If you're in the plugin directory, you can do that with this line:
54+
```python
55+
import will.plugins.API as API
56+
```
57+
Now we can write a function that we want W.I.L.L to execute. All plugin functions should accept 4 arguments. The first will be the first word of the command. The second will be the raw, full text of the command. The third should be *args, and that will contain all of the nlp data that your plugin might want to access. The fourth should be **kwargs, and that will contain metadata about the command. You shouldn't needed this unless you're debugging the plugin framework
58+
```python
59+
def test_func(leader, sentence, *args, **kwargs):
60+
print leader #The first word of the command
61+
print sentence #The entire command
62+
print args['ents'] #A dict of recognized entities
63+
print args['struct'] #A dict of recognized pos tags
64+
print kwargs #Dispatcher debug info
65+
```
66+
Now that we have that function, let's hook it up to the W.I.L.L API with a decorator. There are currently 4 functions inside the api that you can use. The first two go together. `@init`, which will run on initialization of W.I.L.L, and `@shutdown`, which will run as W.I.L.L exits. These do not need the standard arugments in the accompanying functions. Next, we have `@API.subscribe_to_any`. That will, as the name implies, be activated when any command is entered into W.I.L.L. Finally, the most important one. `@API.subscribe_to`. Unlike the others, this requires input data, so W.I.L.L can know under what circumstances to run it. You'll pass it a dictionary containing a neat package of information about the plugin. Included in this dictionary are the name of the plugin, what entities the plugin needs (list of supported entities can be found at https://spacy.io/docs#annotation-ner), what parts of speech the plugin needs, if the plugin needs questions, and any key words that it needs. Here's a sample of the dictionary.
67+
```python
68+
{
69+
"name" : "test",
70+
"ents_needed" : ["PERSON"], #Could also be left empty by writing "ents_needed" : False
71+
"structure" : {"needed":["VERB"]}, #Could also be left empty with "structure" : {"needed":False}
72+
"questions_needed" : False, #Always a bool, True or False if it needs questions or not
73+
"key_words" : ["test"] #Can be left empty with"key_words" : False
74+
}
75+
```
76+
Finally, you can load values in the config by importing will.config. Import it like this:
77+
```python
78+
import will.config as config
79+
```
80+
There are threwe methods available to plugins in config, `load_config`,`remove_config`, and `add_config`. `load_config`takes a header of something already in the config and returns the value. `add_config` updates the config with a dictionary passed to it, and `remove_config` removes takes a header and removes that item from the config. Like so:
81+
```python
82+
import will.config as config
83+
84+
#Add an item to the config
85+
config.add_config({"docs_read" : True})
86+
87+
#Load an item from the config
88+
docs_read = config.load_config("docs_read") #The value you just added
89+
90+
#Remove the item from the config
91+
config.remove_config("docs_read")
92+
```
93+
94+
Now that we've written our function defined the plugin, and familiarized ourself with the methods, let's tie it all together in a file.
95+
96+
`W.I.L.L/plugins/test.py`
97+
```python
98+
import will.plugins.API as API
99+
import will.config as config
100+
101+
#A function that will run on initialization
102+
@init
103+
def on_init():
104+
print "W.I.L.L Started!"
105+
#Add an item into the config
106+
config.add_config({"will_started" : True})
107+
108+
#The dictionary we made earlier
109+
plugin_data =
110+
{
111+
"name" : "test",
112+
"ents_needed" : ["PERSON"], #Could also be left empty by writing "ents_needed" : False
113+
"structure" : {"needed":["VERB"]}, #Could also be left empty with "structure" : {"needed":False}
114+
"questions_needed" : False, #Always a bool, True or False if it needs questions or not
115+
"key_words" : ["test"] #Can be left empty with"key_words" : False
116+
}
117+
118+
#Subscribe the plugin_data dictionary to the function we wrote earlier
119+
@API.subscribe_to(plugin_data)
120+
def test_func(leader, sentence, *args, **kwargs):
121+
print leader #The first word of the command
122+
print sentence #The entire command
123+
print args['ents'] #A dict of recognized entities
124+
print args['structure']['tags'] #A dict of recognized pos tags
125+
print kwargs #Dispatcher debug info
126+
#While we're in the function, why not load the config item we added earlier
127+
will_started = config.load_config("will_started")
128+
print will_started
129+
130+
#A function that will run as will exits
131+
@shutdown
132+
def on_shutdown():
133+
print "W.I.L.L is shutting down"
134+
#Remove the config item
135+
config.remove_config("will_started")
136+
```
137+
138+
Now let's run our plugin! So we can see what's going on, let's use W.I.L.L in the terminal
139+
```python
140+
>>>import will #This might take some time as the nlp models take time to load
141+
>>>will.run()
142+
W.I.L.L Started!
143+
>>>will.main("test this sentence includes Will, a person")
144+
test
145+
test this sentence includes Will, a person
146+
{"Will", "PERSON"}
147+
{'a': 'DT', 'sentence': 'NN', 'this': 'DT', 'is': 'VBZ', 'who': 'WP', ',': ',', 'includes': 'VBZ', 'Will': 'NNP', u'person': 'NN', 'test': 'NN'}
148+
{'signal': 'test', 'sender': _Any}
149+
True
150+
>>>will.exit_func() #This will be called however W.I.L.L exits, you don't need to call it explicitly
151+
W.I.L.L is shutting down
152+
```
153+
And there you have it! A working W.I.L.L plugin!
154+
### Todos
155+
156+
- Add JSON plugin docs
157+
- Add client creation docs
158+
- Chromecast plugin
159+
- Spotify plugin
160+
- Add more structural NLP
161+
- Add more clients
162+
163+
License
164+
----
165+
166+
MIT
167+
168+
These docs made on dillinger.io, off the default template.
169+
170+
171+
172+
173+
174+
[will]: <https://github.com/ironman5366/W.I.L.L>

README.txt

-41
This file was deleted.

will/nlp.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ def entity_recognition(self, parsed_data):
120120
def POS(self, parsed_data):
121121
'''POS tagging'''
122122
tags = {}
123+
string_store = parsed_data.vocab.strings
123124
for token in parsed_data:
124-
tags.update({token.orth_:token.pos})
125+
tags.update({token.orth_:string_store[token.tag]})
125126
return tags
126127
def question_check(self, sentence):
127128
'''Check if the sentence is a question'''

0 commit comments

Comments
 (0)