The check for "this" performed in the case of "this quarter of an hour"
was copy/pasted in a large checkin. The change it made to
daySpecified made no difference since the or in the later code
looked for an unspecified absolute hour. I can come up with no
senseable phrase that matches the conditions and couldn't even
create a nonsensical phrase that made a difference.
Since all of the existing unit tests pass without this code,
I'm going to just remove it.
Verify that skill directory exists before writing to ensure that the
shutdown method doesn't throw exception if a skill is unloaded due to
being removed.
This resolves the Runtime Warning "'mycroft.messagebus.send' found in sys.modules after import of package 'mycroft.messagebus', but prior to execution of 'mycroft.messagebus.send'; this may result in unpredictable behaviour"
Account ID will now be refetched if invalid the first time.
This also adds some general exception handling to avoid client crashing due
to the servers invalid 204 response.
- Fix: isFractional_es() parsed fractions incorrectly
- Update: earlier commit msg suggested another fix:
- Month parsing not fixed
- Several failing tests (skipped) document problem
- TODO and an issue also created
- Substantially improve parse_es.py test coverage
- TODO or comment several found bugs
- Many lines remain uncovered, incl possible bugs
If rendering a chunk of a sentence takes too long time, the audio queue
may run out and trigger the listening.
This moves the listening trigger to after the last chunk.
- Fix bug causing extractnumber_es to return a sum instead of a list
- Add Spanish parser to extract_numbers and extract_number
==== Fixed Issues ====
Closes#2310
==== Tech Notes ====
Further obscures #2056: short_scale and ordinals parameters added to the
Spanish parsers, but they don't do anything. Present for compat only.
There is a TODO for this.
==== Localization Notes ====
It's all Spanish stuff!
This will require a native Spanish speaker to analyze the relationship
between extractnumber and isFractional, and determine why certain
fractions do not parse correctly. There is a TODO for this.
- Remove unreachable conditions from parse_en:1122-1133
- input string passed through clean_string() on line 763
- articles stripped from input before line 1122
- removed conditions relied on presence of "the" in input
- Improved test coverage on parse_en.py by approx 65 statements
- Directly test certain helper functions which are difficult to
invoke indirectly
- Add tests for certain missed conditions
- Approx. 20 uncovered statements remain
Add one more optional parameter: bool clock, always produces
digital clock-like output. "0h 3m" becomes "0:03:00".
Has no effect on resolutions YEARS or DAYS, and MINUTES won't print hrs.
- Companion enum:
mycroft.util.format.TimeResolution
offers YEARS, DAYS, HOURS, MINUTES, SECONDS, or MILLISECONDS
- Will only return ms if MILLISECONDS is chosen. Default: SECONDS
- Update tests
==== Fixed Issues ====
#2333
==== Tech Notes ====
extract_datetime("day after tomorrow") attempted to check the previous
word. This resulted in an index error. Fixed by introducing a nested
condition. Seems to have solved it.
A similar bug is present in other parts of this file, such as line 843.
I have also discovered a number of other oddities, but they may be
outside the scope of this issue. At least Mycroft can now extract from
"day after tomorrow."
==== Localization Notes ====
I haven't checked parsers for any other languages.
Assign hardcoded value from MustacheDialogRenderer.render() to variable.
Fix its value to properly accommodate short dialog files.
Remove superfluous check on lines 104-105 of mycroft.dialog.init
==== Tech Notes ====
The new dialog logic, which prevents Mycroft from repeating itself, uses
a list of recently-spoken lines from the skill's .dialog files.
The size of this list is capped, currently at 3. However, .dialog files
can be shorter than 3 entries. An offset is used to accommodate this.
In the previous commit, the offset was wrong. Now it's 2.
==== Documentation Notes ====
If presented with a .dialog file containing 4 or more entries,
Mycroft will avoid saying the same one for at least a few rounds. If the
dialog file contains only 3 entries, Mycroft will avoid saying the same
line twice in a row. If only 1-2 entries are present in a .dialog file,
Mycroft will just pick one and say it, without retaining a history.
Attempt to use a different line each time a .dialog file is invoked.
==== Tech Notes ====
MustacheDialogRenderer:
- Keep a running list of recently spoken lines (up to 3)
- If there's more than one line in a dialog file, don't repeat lines
- Pop lines from the list when full or when dialog file is running low
==== Documentation Notes ====
Consider encouraging skill authors to include multi-line .dialog files,
as this will help to give Mycroft a more natural feel
This makes sure to shutdown any Timer handling settingsmetadata upload
on skill shutdown to make sure no duplicates are running.
(Easily occurs when a skill gid doesn't match the one sent in skill
manifest)
This captures any unhandled expressions and will at least make sure
they're logged properly. (Exceptions in threads are mostly not printed
to stdout).
This sleeps slightly longer than normal (10 seconds) and then tries to resume
normal operation.
This handles capture portals as well.
The standard connection logic is now
Check outside ip is reachable and after that check that www.google.com
is resolvable and connectable.
TODO: create endpoint on backend with known response to perform check
upon.
Change logic that checked for an internet connection after an issue occurred during initial boot where the old connection check gave a false positive.
Reordered imports to be PEP8 compliant. Minor refactoring to remove issues identified in PyCharm
During skill shutdown remove_all_handlers() was called on all registered
events. This would unregister all global events, such as settings
updating, stop for all skills.
Now the remove only will remove the instance connected to the skills
method.
Pulseaudio allows corking / ducking for streams with prioritized roles
This sets the role for the mycroft speech to "phone" and all other to
"music" if the config tts->pulse_duck is set to true.
- Remove once-logic from the default handler wrapper, no need to do it there.
- Add docstring for handle_wrapper
- add the on_start, on_end handlers and move skill logic to respective
handlers.
- Create separate method for regisetering mycroft system event handlers
- Fix some string concatenations
- Group acknowledge together with speak and speak_dialog
This will recurse down to MycroftSkill class but not include it. for
most skills this will mean only the methods / variables added by the
skill creator
An exception in skill's initialize method would be reraised and cause
the main loading routine to halt. This does not reraise the exception,
instead the instance reference is removed.
Split skill_manager into three separate classes, SkillManager, SkillUpdater and SkillLoader splitting the responsibility into logical units
* Split the SkillManager.__init__ code to determine the download times into a new method
* Make docstrings consistent and PEP257 compliant. Also fixed a couple of spelling errors
* fixed two issues introduced in the previous refactoring
* removed unnecessary assignment of an instance attribute to a local variable
* updated the unit test to mock out code that reaches outside of core, like MSM and the configuration manager.
* add several unittests and refactored load_priority method.
* add a test for the _get_last_modified_date function.
* add "quick" argument to docstring
* removed unused import
* new class containing the logic to periodically update/install skills and send skill manifests to the backend.
* import MsmException from where it is defined, not from the skill manager.
* add some logging to the skill updater
* remove code now in SkillUpdater from SkillManager
* added imports to __init__.py to define the API into the message bus package
* new base class for unit tests and module for reusable mocks
* new skill loader class that will replace the _load_or_reload_skill() method in the SkillManager class.
* moved skill loading logic from core.py into skill_loader.py, resulting in some refactoring of skill loader and skill manager. change unit tests to match.
* added back some spacing that was inadvertently removed.
* change skill tester to use new SkillLoader class.
* Separate reload required check from performing reload to make logic easier
to follow
* Track skills that failed to load to handle infinite loop at first load
if skill fails to load
* Allow reloading skills that has failed to load
* Simplify first load of skills
- create activate, deactivate and unload methods for skill_loader
objects
- add sanity checks before activating and deactivating skills
- Update activation/deactivation test cases
In some instances, the backend returns number setting values as an integer rather than a string.
This has been seen in the wild but has been difficult to replicate. The circumstances under which it happens are still unclear. I was able to semi-consistently have a number returned as int from the [Severe Weather Skill](https://github.com/domcross/severe-weather-information-skill) when editing an unrelated setting. To test, remove the 3 character country code (`[A-Z]{3} - `) from the service options of this skill .
This seems to be the quickest fix for it, but worth investigating further from the backend.
The pairing trigger should only be triggered by the 401 status for the
Mycroft hosted STT backends. Doing it for other STT's is only confusing.
This creates the decorator 'requires_pairing' that can be applied to the STT modules where it's relevant.
This adds the decorator to the MycroftSTT and the MycroftDeepSpeechSTT
This small change adds a check that the intent has been registered
before removing it.
If an unregistered intent was removed padatious would silently throw an
exception due to a list operation error. But when run synchronously from
the skill tester this silent exception was actually loud causing skills
to fail to load.
Major refactoring of the skills startup sequence
- Restructure to a less nested structure
- Remove usage of globals by wrapping a lot of state variables into a class this allows for things like caching a negative pairing status throughout the startup process
Refactors code so no request is sent to backend if the local identity
file is empty / has no uuid. Since if this part is missing core already
knows that it's not paired correctly.
- MycroftSkill and related core functions to mycroft_skill.py
- FallbackSkill to fallback_skill.py
- Add important classes decorators and functions to __init__.py
- move SkillGUI class to the enclosure along with the other enclosure
interfaces
core.py retains the same members as previously by means of imports to
retain backwards compatibility. When most of the available skills starts
using this new structure properly
Message bus config loading is now shared by service and client.
messagebus.client.ws file is still available in case skills are using it. It is a backport that inherits from the new MessageBusClient class. Adds depreciation warning.
- Add module docstring
- Add comment in the init class method about setting up the log level
- Add mycroft.util.log to the readthedocs documentation
- Add comment in the config about the log_level
Checks if the skills haven't been updated for more than 2 weeks or if
the last_download is undefined. last_download may be undefined if
the .msm file is missing or if the list of installed requirements is
missing so skill requirements may be missing.
This also makes sure the skills are normally loaded before the an update
attemt is tried.
Upgrade msm to 0.7.8
Using the new max_threads parameters to MycroftSkillsManager.apply() the
skill loading is reduced to 2 threads if it's during runtime while a
fast update (20 threads) are used if not all default skills are
installed to speed up getting core into a 100% operational state.
A backwards compatibility piece of code creates a hotword from the
listener settings if the listener referes to a non-existing hotword.
This makes sure the generated config doesn't affect the loaded
configuration to avoid extra reloads of precise.
The reload check is now using a more reliable method and only a subset
of the configuration. Currently set to "listener", "hotwords", "opt_in"
and "stt".
pychromecast needed to be updated to fix pip package version conflict
when using streaming google STT.
Minor issues with startup of audio needed to be handled, mainly adding
explicit waits to ensure commands would be accepted
the old "__metaclass__" has been ignored since the switch to python 3
this restores the metaclass functionality by updating it to the new
class kwarg syntax
Pulling method originally implemented in the default Mycroft skill-alarm, but useful by many for
converting a different timezone to whatever the native timezone is on the host machine.
The MycroftSkill.stop() method does not need to be implemented by the majority of skills, no reason to 'require' its implementation with an abstractmethod.
The initial framework for live streaming Speech to Text. STT derived
classes now can report that they support live streaming via their
"can_stream" property. If True, the following member functions will be
called on the object:
stream_start() - Called when a stream is starting. Should setup any
persistent state required to process speech to text.
stream_data(chunk) - Called when a chunk of audio data has been
captured.
stream_stop() - Called when a stream should be stopped. Should tear down
any state setup with stream_start(). Note that this may be called at
anytime (even if stream_start() has not been called).
Note that the execute() API is still used to get the text utterance from
the class.
A typical sequence of calls would be:
stream_start()
stream_data(...)
stream_data(...)
stream_data(...)
stream_data(...)
...
execute(...)
stream_stop()
* Handle DelayRequests when uploading blank settingsmeta
* Move Api methods to DeviceApi
This includes delete, put and get skill settings/meta
* Cache skill settings for 30 seconds
The skill settings are cached to reduce number of requests to the backend and increase skill loading speed.
* Remove _request_other_settings method
The endpoint is not used anymore
* Fix issue when the settingsmeta fails to load
Remove an old reference to "BLANK_META" left behind in the exception handler for failing to load settingsmeta.
When opt in is set and local saving of the file no mtd would be generated and the cause a undefined variable exception. This generates metadata if it's missing
* Restored ability to store wakewords locally
The code that handles the local save of wake words configuration -
"record_wake_words" - was removed some time ago. This restores that
capability.
Add the following to mycroft.conf
{
"listener": {
"record_wake_words": true
}
}
Then restart Mycroft. It should begin saving .wav files under the
/tmp/mycroft_wake_words directory.
The filename, will be filename structure is:
<accountId>_<engine>_<model>_<name>_<sessionId>_<time>.wav
* Add documentation for 'record_wake_words' and improve the doc for
'save_utterances'.
* Catch the new system.gui.user.interaction
This will in turn trigger the gui.page_interaction similar to the page flip but page_number will be None
* Fix issue when adding pages
Seems like appending would fail at times
* Add lock around namespace modifications
* Improve argument description for override_idle
* Log error when creating Padatious
* Update msm to v0.7.6
This handles connection errors during the startup procedure and improves
the skill_gid when no network is available
Padatious is registered as a FallbackSkill and was pushing settings to
the backend.
This change allows Padatious to flag to the MycroftSkill class
that no settings should be created. This is done via the new optional
MycroftSkill parameter use_settings.
When the mimic2 TTS instance is created the phrases from mycroft-core and mycroft-wifi setup (if available) is generated and stored locally (defaults to /opt/mycroft/preloaded_cache but can be changed with the mimic2 config parameter "preloaded_cache"
On startup the cache will be copied into the cache directory to speed up default interactions.
Mycroft-core won't retry for 5 minutes on a 422, 500 or 501 error.
This adds a DelayRequests Exception which will cause the settings
fetching Timer thread to sleep for 5 minutes
* Set default log level to INFO
* Restore echo functionality
- Make sure that the mycroft.debug.log message isn't removed by the
whitelist
- whitelist now only checks the beginning of a message so a whitelisted
"mycroft.audio.service" will allow messages such as
"mycroft.audio.service.play"
* Make MycroftSkill.log track root logger
modify root logger when changing log level will now change the log level
of the skill logger.
* Changes for debugging
* Switched bus logging to use INFO instead of DEBUG so it always displays when turned on
* Add exception output
* Replaced multiple calls into a msg_type variable
The simple audio service can be paused. The audio is "paused" but placing the
audio playback mechanism (usually aplay or mpg123) into the background, kinda
like hitting Ctrl+Z. While in the background that process can no longer react
to the SIGTERM signal. So paused audio has to be brought to the foreground
using SIGCONT, and _then_ sent SIGTERM.
Also added a belt to go with these suspenders and perform a process.kill() if
the audio process doesn't go away after 1 second.
The message returned is a dict of all available audio backends as keys
containing 'supported_uris' listing supported uri types (file:// http://
etc.), 'remote' (bool) True if remote), 'default' (bool) true if the
default audio backend.
Revert "Fix a couple of minor issues intruduced by skill_gid (#2079)"
This reverts commit e046377ce1.
Revert "Merge pull request #2075 from forslund/bugfix/msm_wrapper-license"
This reverts commit 18cfbce0ca, reversing
changes made to 82fa314ce9.
Revert "Feature/skillsmeta gid (#2074)"
This reverts commit 82fa314ce9.
* Fix skill_gid for modified skills
Used the old '_' after device uuid
* Identify skill using gid
When receiving data from server the "identifier" entry is now removed and in it's stead the skill_gid should be used.
This also removes the "fetch other settings" functionallity since that is no longer relevant.
* Add global id basics to settings meta
- All skills will upload a blank settingsmeta
- a skill_gid will be appended to all settingsmeta upload-data
- Added basic function for generating skill_gid
* Use new skill_gid field.
Populate skill_gid directly from metadata
* Separate travis tmp-dirs
- Update travis script to use tempdir for each python version
- Update test script to handle nonstandard tempdirs
- Generate msm folder using tempdir when running create_msm test
* Add title field with pretty name
* Collect and expand "title" as needed
For title use market-place title or name in settings meta or skillname
* Switch skill_manager create_msm test to 19.02
* Remove leading / trailing Skill in display name
Also rename title displayname to match new mycroft-skills-data
* Lock msm_create and mock the name info test_settings
If no match was found for the non-normalized utterance it would jump to
the exception handler for StopIteration skipping the normalized step
altogether
This changes the next/StopIteration system for list comprehensions
Previously Padatious intent matches were performed on non-normalized text, meaning that things like "what's the weather" wouldn't match a Padatious intent but
"what is the weather" would.
The "utterance" in Adapt intent data will still be non-normalized even if the intent match occurred on a normalized utterance. Retaining the existing behavior.
The "intent_failure" data. In there, "utterance" is always the raw version, "norm_utt" is the normalized one.
Also added better debugging info for intent matching to the log.
Also addresses a rare issue with the old code where the Adapt context could
have been updated even if the Adapt intent wasn't actually invoked due to
a higher Padatious intent match.
* Add the SkillGUI method send_event()
Sends raw mycroft.events.triggered messages to the gui for the skills namespace.
Example usage:
self.gui.send_event('event_name' {'param1': 12, 'param2': 'abc'})
* Fix mimic 2 long sentences
Fixes bug in the second and third chunking pass incorrectly by
concatinating strings with lists resulting in chunks of single
characters.
* Handle mimic2 chunking correctly
- Move preprocessing from get_tts() to a method called from tts execute,
this allows all parts to be spoken and the caching to work correctly
- Remove duplicate of phonetic spelling in mimic2_tts
The loose (conf > 0.5) Padatious match was previously occurring as Fallback
priority 99. The AIML fallback at priority 90 would consume lots of
utterances, interferring with many skills. Now Padatious runs at priority
89.
Additionally, added documentation of the intent and fallback system, including
guidelines for priorities.
Much of the code used "en-us" as the default value when not specified.
This limited the internationalization potential. Changing the default
to None and adds the ability to define the default lang code from other
locations in code. E.g.
```python
from mycroft.util.lang import set_default_lang
set_default_lang("en-us")
print("English date: "+nice_date(dt))
set_default_lang("de-de")
print("German date: "+nice_date(dt))
```
This allows easier localization of Skills by having the framework set the default without any changes necessary by the Skill writers.
Other minor changes:
* Changed the default return value of get_gender*() to None instead of False
* Split ADJUST into ADJUST and SET
* Use enum names instead of values.
* Add properties to CommonIoTSkill
* property -> attribute to avoid conflict with builtin
* Add increase and decrease actions
* Fix copy/paste error
The restore_volume would previously unpause the service even if the user just asked for pausing playback.
This separates the paused flag from the pausing/resuming action so lowering/restoring volume doesn't affect the logical pausing state and can check it to determine if lowering/restoring is needed/wanted.
This adds a very simple mechanism for pausing and resuming audio streams
that are actively playing. The process is suspended and resumed when
requested.
This also uses that same method to implement lower_volume()/restore_volume() for simple "ducking" of audio.
Mimic2 voices has several issues:
* Numeric generation was all goofed up for decimal numbers. It was
independently doing number to speech for the values before and after
the period on a decimal number. E.g. 1.100 became "one.one hundred".
Removed local normalization altogether since it is handled
correctly on the Mimic2 server now.
* Sentence splitting was being applied in the middle of things like
numbers or abbreviations. E.g. "I.B.M."
* Chunker algorithms were making unnecessary copies of string arrays
While in there I also:
* Removed several unused imports
* Cleaned up docstrings
* Prefixed private helpers with _
* Added debug logging of mimic2 request text
Padatious was accepting fairly low confidence matches (0.5). This
would match a phrase such as "Where is the Empire State Building?" to the
intent "Where were you born?" (Which is a 0.54 match)
Now there are two passes mad on the Padatious fallback. The first is
looking for high confidence matches (> 0.8). Then other fallbacks -- such
as the CommonQuery fallbacks -- have an opportunity to consume the
utterance. If they don't consume it, Padatious is invoked again with
looser confidence before finally invoking the Unknown fallback.
This commit add the initial translations of core functions for format
numbers: nice_number_es, pronounce_number_es and nice_time_es.
==== Localization Notes ====
NONE - Castillian (Spain's spanish)
Now the eyes go to a khaki color and "< < < LOADING < < <" displays
during the skill startup. When Padatious finishes the first training
we now emit a "mycroft.ready" on the messagebus.
A change to the skill_mark_1 to look for "mycroft.ready" instead of
"mycroft.skills.initialized" provides a good visual change to show that
it is ready for use.
The deprecation warning was firing off at the load of every skill when
the decorators are being iterated through by internal code (which
includes the self.config with an @property). Add check for these
special cases to not show a warning.
The scoring for CommonPlay would favor skills that responded with overly long
matches. E.g. "Huey Lewis and the News" would be considered a better fit than
just "News" for the request "Play the News"
* Deprecate self.config in skills
Skills should contain their own settings, the self.config concept is being
deprecated.
Also removed the defaults set for several old MycroftAI skills. The 19.02
version of these Skills initializes the default values using:
```python
self.settings["key"] = default
```
* Update padatious config to work with the config property.
* Run emitter using threadpool
This moves the thread pool from the websocket client into the eventemitter allowing each registered function to run in a separate thread and not just each event.
This speeds up cases where there is a one to many call such as the common play framework and the upcomming common query framework.
* Add unit tests for threaded event emitter
* Add standard header
* Add standard header
* Add base common_iot_skill
* can_run takes IoTRequest
* Minor cleanup + documentation
* Fix pep8 issues
* Adjust scene and entity registration.
The controller skill is not guaranteed to be alive before
CommonIoTSkills, so we must call for values when it is alive, in
addition to accepting them at any time from other skills.
* Safer parsing
* Address PR feedback
* Add skill_id to register message
* Minor docstring edits
* date and time - for tonight, weekdays
* Updating the previous commit test_extractdatetime_en
* Editing comments for extract_date_time_en
* Generalized as a marker
Expanded this from just handling "weekends" to any day or plural of the day, "weekend", "weekday" or "weekdays".
* Add remove page methods
* Implement SkillGUI.clear()
The method will now remove the namespace entirely from the gui.
This adds the message gui.clear.namespace
* Remove debug prints from SkillGUI
* Correcting docstring
* More docstring changes
* Remove whitespace added by Github webUI
* Attempt to create skill directory if not existing
* Handle missing priority skills
* Minor update of comments
* Handle skill load exception
Make sure an exception while trying to load/reload skill doesn't shutdown thread.
* Handle MsmException during SkillManager creation
If SkillManager can't be created due to an MsmException wait for network connection and retry.
* Update immediately if skill install file is missing
Missing skill install file indicates that this is a new venv and the requirements of the skills will need to be reinstalled.
* Add basic test for skill_manager
Basically only creating the skill_manager but it ensures that msm can be used on all supported python versions
* Update to pyee 5.0.0
- Update requirement
- Make the SkillSettings class hashable
* Update adapt to 0.3.2
* Upgrade websocket-client
* Remove special threading for common query
This ensures no attributes are None and simplifies some checks within the function
Otherwise, if, for instance, there were no 'data' field in a message, when deserializing, the caller would have to check for None
This sends a new system.update.check message when the device is booted and not paired
It is not sent every boot because the command could upgrade across major versions which the user could not want.
- Create a read_vocab_file() function that normal vocab loading and voc_match both uses. This function handles blank lines and comments
- Use a simpler regex instead of word logic to match
- Add a couple of test cases for the method
Several changes to the logging using in all processes:
* Disable logging of bus messages by default (massively cleans up the logs)
* Add "mycroft.debug.log" bus message. It supports the data={"bus": True/False} as well as
data={"log": LEVEL}, where level is a Python logging level.
CLI now supports several commands:
* ```:log level XXX``` where XXX is the name of a standard Python level (e.g. 'debug')
* ```:log bus on``` or ```:log bus off```
* Removed the requirement for "log" in ```:clear log```. ```:clear``` works now.
The mic-level meter that appears in the Mycroft CLI could stop updating in
rare cases when a file I/O operation failed. It would also fail to show
a meter ever if the mic_level file hadn't been created before the CLI was
started.
Previously the voc_match() method had several problems:
* Blank lines in the .voc file would cause it to match all strings
* Comments weren't ignored
* Substrings matched so "book" would match "ok", for instance
Ambiguous times previously used a generally unexpected rule about
when to jump 12 hours when parsing times. Now it follows the rule:
If a time is spoken without am/pm indicator, assume the next time
that hasn't passed was intended.
For example:
"at 7 o'clock"
Would mean 7:00am if spoken at 6:59am, but would mean 7:00pm
if spoken at 7:01am.
* Remove the old single viseme message
Instead a single viseme message is sent
* Correct the spelling of viseme.
Ref: https://en.wikipedia.org/wiki/Viseme
* Remove debug print.
This was probably left in by mistake, removing to clean up the audio log somewhat.
In the case where a network call during the initialization of the
settings poll fails the first time, it would never be tried again.
Now it will retry initialization once a minute.
The settings code worked, but was noisy and generally messy about
a few exceptional but common situations:
* When the .mycroft/skills/<SkillName> folder didn't already exist
* When network timeouts and such occcurred
I also slipped in a couple trivial code cleanups for an unused variable
and a log message.
* New formatters: nice_duration() and join_list()
Adding two new formatting functions:
* nice_duration(duration, lang="en-us", speech=True)
Accept seconds or duration and produce a nice sounding duration.
Example: nice_duration(61) == "one minute one second"
nice_duration(61, speech=False) == "1:01"
* join_list(items, connector, sep=None, lang="en-us")
Example: join_list(["a", "b", "c"], "and") == "a, b and c"
This includes a translation helper that uses text files in the
mycroft/res/text/LANG/ directory, such as "second.word".
This extracts the logging logic that was being used in a few places to
indicate certain parcing functions are not supported in particular
languages, and adds the logging to extract_duration.
- Move "save_utterenaces" comments to correct block
- Correct information, records utterance not wakeword
- replace "record_utterances" with the new "save_utterances"
Change to match the documented and more intuitive name "save_utterances",
but add backwards compatibility code to support the original
"record_utterances".
Making things weak private, to limit surface area of support. As things
become increasingly stable/tested/useful, it may make sense to open them
up, but for now, keeping them private will limit risk.
This is in support of issue-1959.
After many changes, things had gotten a little disorganized, and the
docs were a little out of date. This brings them up to date.
This is in support of issues-1959.
This improves the utility of the _ReplaceableNumber class, and updates
most of the number parsing functions to take tokens rather than text.
This simplifies the interactions between many of the functions, as there
is no need to convert back and forth between text and tokens.
This also adds some tests. Note that there are a few regressions that
will be fixed in a subsequent commit.
This was calling convert_words_to_numbers and parsing out the resuling
numbers, which was a simple way of getting the numebrs in order, but it
choked on anything that didn't match the regex being used to parse
numbers, in particular numbers of the form '6e18'. The better solution
is to directly use extract_numbers_with_text (which now sorts by
start_index) and get the values from there directly.
This is in support of issues-1959.
"Five hours seven and a half minutes" was parsing as 5.5. This is
resolved. Multiple fractions/decimals still cause problems, e.g.
convert_words_to_numbers("seven and a half and nine and a half")
Out[5]: '7 and a 0.5 and 9 and a 0.5'
This is in support of issues-1959.
* Add tests for DialogLoader
* Handle Path/PosixPath
LOG messages when files/directories were missing would fail when a PosixPath/Path object was sent to as argument. This uses format to get the correct string representation.
* Add test for dialog.get()
Slight refactoring to accommodate for this in a nice way. Created
function connect_to_mycroft() handling fetching the config and
connecting to the mycroft messagebus since these are related and the
order is important to maintain for it to work.
* Refactor mimic2 to use the shared tts architecture
* Make sure the queue is cleared
- Add a convenience method grouping clear_queue and clear_visemes
- The start time is now set before the lock to allow multiple speech requests queued before the stop signal to also be cancelled
- Make sure the any pending TTS generation is cleared from the queue by calling tts.clear() when breaking from the chunking loop.
To simplify the process of adding an idle page to a skill the decorator "resting_screen_handler" was added. In a skill class the decorator can be applied to a method to register it to handle idle.
@resting_page_handler("My Idle Page")
def handler(self, message):
...
The decorator will Register the method with the Mark-2 skill and perform all communications needed to make it work smoothly.
* Add new api command to send visemes as single list. This allows more efficient use of the messagebus and gives implementors flexibility in how they handle the visualization.
* Switch mark1 to use viseme_list
The wrong method was registered, instead of the wrapped function call
the original method was registered. This led to not being able to
unregister fallbacks.
A small bug caused things like "two hundred twenty" to return only the
"hundred tenty" for the text. This has been fixed.
extract_numbers_with_text was updated to deal with the new return types
of the functions it depends on. Specifically, it accounts for the start
and end index values.
This is in support of issues-1959.
Previously it was assumed that the orgiginal text would be enough to
determine where in a string a number should go, however, in some
scenarios, that does not work, and results in the wrong values being
parsed.
A different, and smarter approach is being taken now, in which the
original string is initially split into a list of tuples of
(index, word) where index is the index of the word within the string.
All subsequent processing is done on these tuples, meaning we always
know exactly where the words were in the orginal string. This should
make text replacement perfect, as we can always sub out the exact,
correct words, based on their indicies.
extract_number_with_text_en now returns the number parsed, the text that
represents the number, the start index, and the end index.
Things are not yet working perfectly. Here is roughly the current state
of the world:
from mycroft.util.lang.parse_en import *
extract_number_with_text_en("this is some two hundred thousand twenty
two hours")
Out[3]: (200022, 'hundred thousand twenty two', 4, 7)
extract_number_with_text_en("this is some twenty two hours")
Out[4]: (22, 'twenty two', 3, 4)
extract_number_with_text_en("this is some twenty hours")
Out[5]: (20, 'twenty', 3, 3)
extract_number_with_text_en("this is some two and a half hours")
Out[6]: (2, 'two', 3, 3)
extract_number_with_text_en("this is some two point five hours")
Out[7]: (2, 'two', 3, 3)
The list of tuples is a bit of a hassle to deal with. In a future
commite the will be replaced with dictionaries, or even better, Token
objects, that contain the word and it's index. This would make the
code easier to reason about (removing lots things like words[0][1]
which has no meaning without deep understanding of the code).
This is in support of issues-1959.
Articles (a, an, the) that appeared immediately before the number were
included in the returned text. This fixes those issues.
The solution isn't super clean - it craetes a new function to wrap the
old one (unavoidable, since the articles can be needed for fractions),
and splits the returned string, the strips leading artivles.
Since strings are immutable, this is probably not super efficient. Might
be better to eventually use lists as much as possible, and only create a
string at the end (though the lists will come with their own problems,
so that could turn out to be a wash). In any case, this works for now.
Issues fixed:
Lists, e.g. "some words one two three" would return (3, "one two three")
Negaitve words were not included in output, e.g. "negative five" would
return (-5, "five").
This is in support of issues-1959.
Any articles (a, an, the) appearing before the number would be included
in the text, e.g. "set a timer for eight minutes" returned:
(8, 'a eight')
This fix clears the number words list if no number words have been
found. Note that articles can't simple be filtered, as they are
often a part of the numebr (e.g. three and a half).
This is in support of issues-1959.
Methods implemented include:
extract_number_with_text
extract_numbers_with_text
convert_words_to_numbers
extract_duration
This is in support of issues-1959. This continues the work of
returning the relevant text that corresponds to a number
parsed from a string.
This is in support of issues-1959. This begins the work of returning the
relevant text that corresponds to a number parsed from a string. Here's
a sample showing the basic functionality/state of the world (showing
some of the remaining cases to handle)
>>> from mycroft.util.lang.parse_en import *
>>> extractnumber_en_with_text("three hours twenty minutes")
(3, 'three')
>>> extractnumber_en_with_text("twenty minutes")
(20, 'twenty')
>>> extractnumber_en_with_text("twenty five minutes")
(25, 'twenty five')
>>> extractnumber_en_with_text("two hundred twenty five minutes")
(225, 'two hundred twenty five')
>>> extractnumber_en_with_text("three and a half minutes")
(3.5, 'three and a half minutes')
>>> extractnumber_en_with_text("three point five minutes")
(3.5, 'three point five minutes')
==== Tech Notes ====
Checks if the word being parsed is relevant to number parsing. If it is
not, and we have already found number words, we return what we have. If
it is, we add it to a list of words representing the current number
being parsed.
==== Documentation Notes ====
The old implementation of extractnumber_en seems to generally return the
last number in the text. This change will cause the first number to be
returned.
This is part of a refactor of extractnumber_en, with the ultimate
goal of making it easier to maintain and extend (should also
improve perf). This is in support of issues-1959.
This is part of a refactor of extractnumber_en, with the ultimate
goal of making it easier to maintain and extend (should also
improve perf). This is in support of issues-1959.
All tests (minus extract_duration, which has not yet been implemented)
are passing at this stage.
This is part of a refactor of extractnumber_en, with the ultimate
goal of making it easier to maintain and extend (should also
improve perf). This is in support of issues-1959.
All tests (minus extract_duration, which has not yet been implemented)
are passing at this stage.
Audiotest now prints the device and samplerate used as well as the commandline used to playback the audio for easier debugging if things doesn't work as intended.
This is part of a refactor of extractnumber_en, with the ultimate goal
of making it easier to maintain and extend (should also improve perf).
This is in support of issues-1959.
Begins a refactor of extractnumber_en, with the ultimate goal of making
it easier to maintain and extend (should also improve perf). This is
in support of issues-1959.
* Add communication from GUI to skills
- "set" events from Qt will set/update a variable in the skills .gui member
- It's possible to add general event handlers using self.gui.register_handler()
- Moved registration of skill_id to just after skill init
* Ensure that simultaneously writes doesn't occur
Wrap WebSocketHandler.write_message() with a lock in an attempt to handle "buffererror: existing exports of data: object cannot be re-sized."
* Add better logging to help debug disconnect issue
* Allow overriding the idle page
SkillGUI.show_page() and SkillGUI.show_pages() now takes an optional
override_idle parameter. This is used as a hint by the mark-2 skill
and if possible the idle screen will not be shown.
* Improve debugging using Logger
* Raise exception when sending a non-existing gui page
* Restore running state to new connections
When a GUI is connected data and running namespaces are synchronised and
shown.
This refactors the code quite a bit moving the GUI state from the GUIConnection
object to the Enclosure.
The GUIConnection object does the handles the sync in the on_connection_open()
method.
* Add gui.page_interaction message
Currently triggered on page change on the display.
* Handle message when gui changes sessionData
* Check if socket exists on gui before sending data
* Increase port on each failure and retry
- Adds RemoteAudioBackend class, which is used to differentiate between
Remotes and local audio backends
- When searching for audio backends the backends are storted to first
check local ones and secondly remote ones
If we are missing the ".mycroft_cli.conf" file we print a message to the
user informing them that we are ignoring the missing file along with a stack trace. The stack trace is really not necessary so this removes it.
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
To avoid UnicodeDecodeError's when opening files tell Python that we
want to open the file as a utf8 encoded file.
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Ctrl+C was not being properly handled by the CLI, resulting in an unclean
shutdown and other unexpected consequences -- e.g. a
"./start-mycroft.sh debug" would kill the background processes on exit. The
KeyboardException was never being triggered.
Now the SIGINT is being captured and Ctrl+C behaves (as intended) just like
pressing Ctrl+X.
This moves the thread pool from the websocket client into the eventemitter allowing each registered function to run in a separate thread and not just each event.
This speeds up cases where there is a one to many call such as the common play framework and the upcomming common query framework.
The audioservice can now jump forward and backward in the audio stream/file
The functionality is accessed via the audioservice class's seek_forward(),
seek_backward() and seek() methods
* Try to improve stability
- Remove sync_active
- Update the way variables are sent to the gui
* Do not show full path for pages
The cli now shows the basename of the current page to make it easier to
determine if the correct page is displayed.
* Make elements in loaded list named tuples
This makes the intent of the code a bit cleaner.
Normally Mycroft will use the default PortAudio input device as the
microphone input for the user. However in some cases there is reason
to specify a different input.
The "device_index" under the "listener" section in mycroft.conf has
always allowed a user to select the microphone explicitly. But on
some systems the indices can change from reboot to reboot. So this
adds the "device_name" setting. If it exists (and the "device_index"
has not been specified explicitly), a regex match will be run against
the PortAudio device names.
When "device_name" is used, the voice.log will contain a listing of
the devices as they are tested. This can be used to debug if a
name isn't matching as expected.
EXAMPLES:
/etc/mycroft/mycroft.conf
```
{
"listener": {
"device_name": "aawsrc"
}
}
```
Would find a match against "aawsrc" or "aawsrcplug". To force a specific
match, you can use a regex such as "aawsrc$".
/etc/mycroft/mycroft.conf
```
{
"listener": {
"device_index": 2
}
}
```
The PortAudio device index specified will be used.
Names and indexes for PortAudio are difficult to guess. The simplest way to
view them is either enter a value for "device_name" and look at the names
which appear in the log when starting Mycroft, or to run a simple program
such as:
```python
import pyaudio
pa = pyaudio.PyAudio()
for i in range(pa.get_device_count()):
dev = pa.get_device_info_by_index(i)
print((i, dev['name'], dev['maxInputChannels']))
```
* Fix mimic2 negative numbers
Make the regex extracting numbers also match negative numbers when preparsing phrases sent to the mimic2 service
* Update pronounce_number to use "minus" for negatives
After discussion in the chat it was suggested to use "minus" for negatives as default.
When scientific notation is used the term "negative " is still used.
Several additions to the GUI protocol support
These changes allow switching between pages successfully with the current
mycroft-gui widget:
* Optimized commands to handle the active skill list
* MycroftSkill.gui.show_pages(list, idx) allows multiple-pages to be displayed
at a time starting with the given index visible.
* Merge SkillGUI.show_page with show_pages
This limits code duplication and makes things a bit more maintainable.
* Do not reload on changed .qmlc files
* Make EnclosureGeneric derive from Enclosure
* Update show function to match mycroft-gui-app
- adds internal representation of all loaded skills
- uses new commands to switch between pages and namespaces
* Add Extra debug output in enclosure
- Log if starting websocket fails
- Log the sending of page info in more detail
* Update GUI Debug client in CLI
- The CLI GUI now handles the new messages for switching pages
- Handle different data types better by using format instead of string concatenation
* Disable syncing code.
The sync code at startup outdated and needs to be reworked. Disabling it for now
to allow better interaction.
* Minor cleanups
- do not inherit from object
- use format instead of string concatenations
- remove duplicated self.loaded
- correct private member access
* Refactor GUIConnection.show()
Move the actions into separate methods for better overview of the logic
* Flipped "valid_file" to become "ignored_file"
The ability to "barge-in" has been lacking from Mycroft Core. The Mark 1
microphone was unable to support this due to physical limitations, but the
Mark II and other implementations with more advanced mic tech which can
hear over themselves are able to continuously listen.
To enable this while retaining backwards compatibility with simpler mic.py
systems, there are now two mycroft.conf values:
{
"listener": {
"mute_during_output" : true,
"duck_while_listening" : 0.3
}
}
The above values are defaults, and implementers will likely override them
using the /etc/mycroft/mycroft.conf file when appropriate.
The duck_while_listening setting is currently handled in Mycroft's
skill-volume. The mute_during_output is handled within mycroft-core itself.
- Add overridable stop() method to HotwordEngine Class
- Add stop implementation to precise shutting down the runner
- Call wakeword_recognizer.stop() before reloading the listener configuration
Several small changes based on the code review feedback:
* Drop '_' from classes like Enclosure_Mark1
* Adopt Python 3 style for class definitions and don't explicitly list '(object)'
* Slightly better documentation
* Moved MycroftSkill.show_html() to SkillGUI, resulting in code like self.gui.show_page('Weather.qml')
* Renamed SkillGUI.__dict to SkillGUI.__session_data. This better reflects the
how values are accessed in the QML.
Adds support for negotiating best answer for a questions
Currently three levels of confidence are defined
EXACT: If the query could be identified exactly and a response is returned.
Example: The cockail skill could find a cocktail in the query that exists in
it's database.
CATEGORY: A category of questions the skill handles could be identified.
Example: The wiki-data skill can identify that the question is regarding
A date of birth and finds an answer.
GENERAL: A general question and answer service could parse the question.
Example: The wolfram alpha skill got a match for "How tall is Abraham
Lincoln".
The QML files are typically not translated like other Mycroft resources,
they have internal translation tools. And at times there are other
resources that don't need to be translated all the time, for example
color strings like "AliceBlue" which might be used by non-English
speakers.
So now the translation mechanism looks for resource file X as follows:
1) Look for <res_dir>/<lang>/X
2) Look for <res_dir>/X
3) Look for anywhere under locale/<lang>/.../X
And now the show_page() method starts looking for resources under the skill/ui folder.
is kept in order, but old namespaces/skills are never culled.
* The active namespace list is synced on a GUIConnection level
* QML display requests now are sent as a list instead of a single entry, i.e.
with "gui_urls" instead of "gui_url". Currently a skill can only send a single
QML, however.
* Change CLI GUI client to handle "gui_urls" instead of "gui_url"
Make sure the older version of the install skill will still work. The SettingsManager.load/write_skills_data() will return the version 0 format of the skills_data and the write_skills_data() will convert to the version 1 format before doing the write.
- Lock msm when doing an update
- Add device enpoint for uploading skills.json
- Add configuration value for skill store updates
- Upload skills manifest after update
The GUI client built-in to the CLI now has these features:
* Activate/deactivate via Ctrl+G
* GUI 'window' shows active page title and all namespace variables
* Add fool-proof primitive draw(x,y, msg) that takes care of clipping, and padding
Further fleshing out of the GUI mechanisms
* Support for data and page from Mycroft -> GUIConnection
* Add a 'reconnecting' event for the messagebus
* Add MycroftSkill.show_url()
* Plumb MycroftSkill.gui into the messagebus
* Implement MycroftSkill.gui dictionary
CLI extensions for the GUI:
* Can now act as a simple GUIConnection
* Minor revamp of messagebus connection, provides kinder handling when
messagebus isn't found or ready.
* BUGFIX: An empty filter would filter ALL messages
* BUGFIX: Input wider than the screen would cause a crash
* BUGFIX: "filter" or "find" with no param would filer "filter" or find "find"
add support for decades, centuries, millemniums
add support for "within the hour", "in a second/minute",
add support for "a couple time_unit" and "a couple of time_unit"
The common play skill sends a stop message in the CPS_start(), if the play message is sent too close to the stop message it may be executed before the stop message causing playback to immediately stop.
To circumvent this a 1 second stop ignore time is added.
Still very much a work in progress.
For understand and testing, here is the sequence:
STEP 1: GUI announces itself
* Connect to the main Mycroft messagebus
* Send: "mycroft.gui.connected" with data { "gui_id": XXX } where XXX is a uniq ID (uuid)
STEP 2: Mycroft creates GUI socket
* Mycroft extracts the gui_id
* Mycroft prepares a socket and announces its availability on the Mycroft messagebus with:
self.bus.emit(Message("mycroft.gui.port",
{"port": self.GUIs[gui_id].port,
"gui_id": gui_id}))
STEP 3: GUI connects
In python, a very minimal test socket handler on the GUI side would look like this
from websocket import create_connection
port = 18181 (from the message above)
ws = create_connection("ws://0.0.0.0:"+port+"/gui")
ws.send("Hello, World")
print("Sent")
print("Receiving...")
result = ws.recv()
print("Received '%s'" % result)
ws.close()
Enclosures
* Create a mechanism to instantiate unique Enclosure classes, depending on the platform found in the SYSTEM mycroft.conf
* Implement a generic Enclosure, which support the new GUI protocol
* Implement a Mark 1 Enclosure (expects the serial connection to an Arduino)
* Implement the start of a Mark II enclosure
* Implement a generic enclosure (no screen)
* Implement the GUI announcement and protocol basics
MycroftSkill
* Implement the basis of the GUI-controlling interfaces. Namely:
- MycroftSkill.show_text()
- MycroftSkill.show_image()
- MycroftSkill.show_html()
- MycroftSkill.show_page()
- MycroftSkill.gui to set values for page displays.
Configuration
* Add "gui_websocket" to the mycroft.config.py
The registered intents are now stored in a list. When a detach_skill message is received the list is checked for matching intents and the intents are removed