Skip to content

Commit

Permalink
Merge branch 'oa-next' into oa-master
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuashort committed Jun 18, 2018
2 parents cb60ffc + 451e0f3 commit e1c9261
Show file tree
Hide file tree
Showing 41 changed files with 1,322 additions and 766 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# OA files
mind/**/cache

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
41 changes: 41 additions & 0 deletions INSTALL.macos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Prerequisite: homebrew (https://brew.sh)

# Basic System Dependencies

## Install Python3

`brew install python`

# Python Modules

`pip3 install requests`

# Open Assistant Modules

## Speech Recognition

### gstreamer

note the options: python3 support, no python2

`brew install gst-python --with-python --without-python@2`

support for autoaudiosrc

`brew install gst-plugins-good`

### sphinx

Build tools

`brew install autoconf libtool automake swig`

sphinxbase

`git clone https://github.com/cmusphinx/sphinxbase.git`
`./autogen.sh && make install`

pocketsphinx

`git clone https://github.com/cmusphinx/pocketsphinx.git`
`./autogen.sh && make install`
Empty file added __init__.py
Empty file.
64 changes: 64 additions & 0 deletions __main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# OpenAssistant 0.04
# 2016 General Public License V3
# By Andrew Vavrek, Clayton G. Hobbs, Jezra

import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


if __name__ == '__main__':

import sys, os

# Parse command-line options,
# use `Config` to load mind configuration
# command-line overrides config file
from .util.args import _parser as arg_parser
args = arg_parser(sys.argv[1:])
if args.debug:
logging.root.setLevel(logging.DEBUG)
logger.debug("Arguments: {args}".format(args=args))


# A configured Assistant
if args.agents_dir is not None:
agents_path = os.path.realpath(args.agents_dir)
logger.info("Agents Path: %s" % agents_path)
sys.path.insert(0, agents_path)

if args.agent is not None:
import importlib
A = importlib.import_module(args.agent)
logger.info("Loading {}".format(A))
a = A.__call__()


#
# TODO: remove
#

from gi.repository import GObject

# Initialize Gobject Threads
GObject.threads_init()

# Create Main Loop
main_loop = GObject.MainLoop()

# Handle Signal Interrupts
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

# Start Main Loop
try:
main_loop.run()

except Exception as e:
print(e)
main_loop.quit()
sys.exit()

#
# End Questionable dependencies
#
Empty file added abilities/__init__.py
Empty file.
47 changes: 47 additions & 0 deletions abilities/calculate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from itertools import groupby

from core import oa

from abilities.core import info
from abilities.interact import say

def isNum(s):
return s.replace('.', '').isdigit()

def expr2str():
""" Convert a numerical expression into a string. """
ret = ''
info(oa.sys.calc_opers.values())
for k, g in groupby(oa.sys.expr, lambda x: ((x in oa.sys.calc_opers.values()) and 1) or 2):
l=list(g)
if len(l) > 1:
if k == 1:
raise Exception('two opers')
else:
sr='(' + l[0]
for x in l[1:]:
if isNum(x):
sr += '+' + x
else:
# 'hundreds, thousands so on'
sr += x
ret += sr + ')'
else:
ret += l[0]
return ret

def add2expr(s):
# Check for calculator. Move to a numbers definition file.
# For numbers, add sum operator.
oa.sys.expr.append(s)

def calculate():
ret = expr2str()
info(oa.sys.expr)
info('expr=' + ret)
try:
say(eval(ret))
except:
say('Error. Wrong expression. ' + ret)
# Clear the expression.
oa.sys.expr = []
77 changes: 77 additions & 0 deletions abilities/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import threading

from core import oa, queue, Stub
from core.util import isCallable, bytes2gb


""" CORE FUNCTIONS """

def thread_name():
""" Return the current thread name. """
return threading.current_thread().name.split(' ')[0]

def current_part():
""" Return the part name which is associated with the current thread. """
name = thread_name()
ret = oa.core.parts.get(name, None)
if ret is None:
err = '%s Error: Cannot find a related part' %name
info(err)
raise Exception(err)
return ret

def call_function(func_or_value):
""" A helper function. For Stubs, call `perform()`.
For other functions, execute a direct call. """
if isCallable(func_or_value):
if isinstance(func_or_value, Stub):
return func_or_value.perform()
else:
return func_or_value()
else:
return func_or_value

def info(*args, **kwargs):
""" Display information to the screen. """
string = "[{}]".format(thread_name()) + ' '
if args:
string += ' '.join([str(v) for v in args]) + '\n'
if kwargs:
string += '\n'.join([' %s: %s' %(str(k), str(v)) for k, v in kwargs.items()])
if oa.console and not oa.core.finished.is_set():
oa.console.wire_in.put(string)
else:
print(string)

def get(part = None, timeout = .1):
""" Get a message from the wire. If there is no part found, take a message from the current wire input thread. (No parameters. Thread safe) """
if part is None:
part = current_part()
while not oa.core.finished.is_set():
try:
return part.wire_in.get(timeout = timeout)
except queue.Empty:
pass
raise Exception('Open Assistant closed.')

def put(part, value):
""" Put a message on the wire. """
oa[part].wire_in.put(value)

def empty(part = None):
""" Remove all messages from `part.wire_in` input queue.
(No parameters. Thread safe) """
if part is None:
part = current_part()
try:
while True:
part.wire_in.get(False)
except queue.Empty:
pass

def quit_app():
quit(0)

def close():
""" Close Open Assistant. """
quit()
47 changes: 47 additions & 0 deletions abilities/interact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import keyboard

from core import oa
from abilities.core import call_function, put
from abilities.system import find_file


def answer(text):
""" Save the return function parameter and switch to previous mind. """
text = text.lower()
func = oa.mind.user_choices.get(text, None)
if func:
call_function(func)
oa.mind.switch_back()

def yes_no(msg, func):
""" Receive a yes or no answer from the user. """
say(msg)
user_answer('yes_no', {'yes': func})

def user_answer(mind_for_answer, choices):
""" Within any `mind` we will receive a one word answer command (voice, file path, etc, any) from the user. """
mind(mind_for_answer, 0) # No history.
oa.mind.user_choices = choices

def say(text):
""" Text to speech using the `oa.audio.say` defined function. """
text = call_function(text)
oa.sys.last_say = text

# Put message into voice.
put('voice', text)

def keys(s):
""" Hook and simulate keyboard events. """
if '+' in s:
keyboard.press_and_release(s)
else:
keyboard.write(s)

def play(fname):
""" Play a sound file. """
put('sound', find_file(fname))

def mind(name, history = 1):
""" Switch the current mind to `name`. """
oa.mind.set_mind(name, history)
59 changes: 59 additions & 0 deletions abilities/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from core import oa

from abilities.core import info, put
from abilities.interact import say
from abilities.system import find_file, sys_exec

def activate(s):
""" Activate a specific window. """
if oa.sys.os == 'win':
w = WindowMgr()
w.find_window_wildcard('.*' + s + '.*')
w.set_foreground()
else:
raise Exception('`Activate` is unsupported.')

def close(s):
""" Close an application by a window or process name.
A partial window name will work, for example: 'note*'. """
say('- Unable to close %s for now.' %s)
pass

def volume(move = 2):
""" Change volume level.
Positive `move`: Volume Up
Negative `move`: Volume Down
"""
if oa.sys.os == 'win':
# Up by 2.
if move > 0:
# Volume up.
key = chr(175)
else:
move =- move
key = chr(174)

while move > 0:
wshell.SendKeys(key)
move -= 2

elif oa.sys.os in ('linux','mac'):
if move > 0:
sys_exec('pamixer --increase %d' %move)
else:
sys_exec('pamixer --decrease %d' %(-move))
else:
info('Unknown operating system.')

def mute(mute = True):
""" Mute or unmute speakers. """
if oa.sys.os == 'win':
wshell.SendKeys(chr(173))
elif oa.sys.os in ('linux', 'mac'):
sys_exec('amixer set Master %smute' % (((not mute) and 'un') or ''))
else:
info('Unknown operating system.')

def unmute():
""" Unmute speakers. """
mute(False)
Loading

0 comments on commit e1c9261

Please sign in to comment.