mirror of
https://github.com/leon-ai/leon.git
synced 2024-10-03 20:57:55 +03:00
chore: init
This commit is contained in:
commit
ed093bf654
23
.babelrc
Normal file
23
.babelrc
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}]
|
||||
],
|
||||
"plugins": [
|
||||
["module-resolver", {
|
||||
"alias": {
|
||||
"@@": ".",
|
||||
"@": "./server/src"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@@": ".",
|
||||
"@": "./server/src"
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
25
.changelogrc
Normal file
25
.changelogrc
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"app_name": "Leon",
|
||||
"sections": [
|
||||
{
|
||||
"title": "BREAKING CHANGES",
|
||||
"grep": "BREAKING"
|
||||
},
|
||||
{
|
||||
"title": "Features",
|
||||
"grep": "^feat"
|
||||
},
|
||||
{
|
||||
"title": "Bug Fixes",
|
||||
"grep": "^fix"
|
||||
},
|
||||
{
|
||||
"title": "Performance Improvements",
|
||||
"grep": "^perf"
|
||||
},
|
||||
{
|
||||
"title": "Documentation Changes",
|
||||
"grep": "^docs"
|
||||
}
|
||||
]
|
||||
}
|
151
.circleci/config.yml
Normal file
151
.circleci/config.yml
Normal file
@ -0,0 +1,151 @@
|
||||
version: 2
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: ~/project/leon-ai/leon
|
||||
docker:
|
||||
- image: leonai/ci:latest
|
||||
environment:
|
||||
LC_ALL: C.UTF-8 # Fix https://click.palletsprojects.com/en/7.x/python3/#python-3-surrogate-handling
|
||||
LANG: C.UTF-8 # Fix https://click.palletsprojects.com/en/7.x/python3/#python-3-surrogate-handling
|
||||
PIPENV_PIPFILE: bridges/python/Pipfile
|
||||
|
||||
jobs:
|
||||
check-stack:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Checking Node.js
|
||||
command: node --version
|
||||
- run:
|
||||
name: Checking npm
|
||||
command: npm --version
|
||||
- run:
|
||||
name: Checking Python
|
||||
command: python3 --version
|
||||
- run:
|
||||
name: Checking Pipenv
|
||||
command: pipenv --version
|
||||
- persist_to_workspace:
|
||||
root: ~/project/leon-ai
|
||||
paths:
|
||||
- leon
|
||||
|
||||
install-npm-dep:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/project/leon-ai
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-leon-ai-leon-{{ .Branch }}-{{ checksum "package-lock.json" }}
|
||||
- v1-leon-ai-leon-{{ .Branch }}-
|
||||
- v1-leon-ai-leon-
|
||||
- run:
|
||||
name: Installing npm dependencies
|
||||
command: npm install
|
||||
- save_cache:
|
||||
key: v1-leon-ai-leon-{{ .Branch }}-{{ checksum "package-lock.json" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- persist_to_workspace:
|
||||
root: ~/project/leon-ai
|
||||
paths:
|
||||
- leon
|
||||
|
||||
init:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/project/leon-ai
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-leon-ai-leon-{{ .Branch }}-{{ checksum "bridges/python/Pipfile.lock" }}
|
||||
- v1-leon-ai-leon-{{ .Branch }}-
|
||||
- v1-leon-ai-leon-
|
||||
- run:
|
||||
name: Setting up
|
||||
command: npm run postinstall
|
||||
- save_cache:
|
||||
key: v1-leon-ai-leon-{{ .Branch }}-{{ checksum "bridges/python/Pipfile.lock" }}
|
||||
paths:
|
||||
- bridges/python/.venv
|
||||
- persist_to_workspace:
|
||||
root: ~/project/leon-ai
|
||||
paths:
|
||||
- leon
|
||||
|
||||
lint:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/project/leon-ai
|
||||
- run:
|
||||
name: Linting
|
||||
command: npm run lint
|
||||
|
||||
test-json:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/project/leon-ai
|
||||
- run:
|
||||
name: JSON testing
|
||||
command: npm run test:json
|
||||
|
||||
test-e2e:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/project/leon-ai
|
||||
- run:
|
||||
name: End-to-end testing
|
||||
command: npm run test:e2e
|
||||
|
||||
test-unit:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/project/leon-ai
|
||||
- run:
|
||||
name: Installing offline STT
|
||||
command: npm run setup:offline-stt
|
||||
- run:
|
||||
name: Installing offline TTS
|
||||
command: npm run setup:offline-tts
|
||||
- run:
|
||||
name: Unit testing
|
||||
command: npm run test:unit
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
install-test:
|
||||
jobs:
|
||||
- check-stack
|
||||
- install-npm-dep:
|
||||
requires:
|
||||
- check-stack
|
||||
- init:
|
||||
requires:
|
||||
- check-stack
|
||||
- install-npm-dep
|
||||
- lint:
|
||||
requires:
|
||||
- check-stack
|
||||
- install-npm-dep
|
||||
- init
|
||||
- test-json:
|
||||
requires:
|
||||
- check-stack
|
||||
- install-npm-dep
|
||||
- init
|
||||
- test-e2e:
|
||||
requires:
|
||||
- check-stack
|
||||
- install-npm-dep
|
||||
- init
|
||||
- test-unit:
|
||||
requires:
|
||||
- check-stack
|
||||
- install-npm-dep
|
||||
- init
|
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
42
.env.sample
Normal file
42
.env.sample
Normal file
@ -0,0 +1,42 @@
|
||||
# Language currently used
|
||||
LEON_LANG=en-US
|
||||
|
||||
# Current env
|
||||
LEON_NODE_ENV=development
|
||||
|
||||
# Server
|
||||
LEON_SERVER_HOST=localhost
|
||||
LEON_SERVER_PORT=1337
|
||||
|
||||
# Web app
|
||||
LEON_WEBAPP_HOST=localhost
|
||||
LEON_WEBAPP_PORT=4242
|
||||
|
||||
# Time zone (current one by default)
|
||||
LEON_TIME_ZONE=
|
||||
|
||||
# Enable/disable after speech
|
||||
LEON_AFTER_SPEECH=false
|
||||
|
||||
# Enable/disable Leon's speech-to-text
|
||||
LEON_STT=false
|
||||
# Speech-to-text provider
|
||||
LEON_STT_PROVIDER=deepspeech
|
||||
|
||||
# Enable/disable Leon's text-to-speech
|
||||
LEON_TTS=false
|
||||
# Text-to-speech provider
|
||||
LEON_TTS_PROVIDER=flite
|
||||
|
||||
# Enable/disable collaborative logger
|
||||
LEON_LOGGER=true
|
||||
|
||||
# Path to the Pipfile
|
||||
PIPENV_PIPFILE=bridges/python/Pipfile
|
||||
|
||||
# Path to the virtual env in .venv/
|
||||
PIPENV_VENV_IN_PROJECT=true
|
||||
|
||||
# Fix https://click.palletsprojects.com/en/7.x/python3/#python-3-surrogate-handling
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
39
.eslintrc.json
Normal file
39
.eslintrc.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"extends": "airbnb-base",
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"globals": {
|
||||
"io": true,
|
||||
"webkitSpeechRecognition": true
|
||||
},
|
||||
"plugins": [
|
||||
"import",
|
||||
"jest"
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"babel-module": { }
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"no-multi-assign": "off",
|
||||
"no-trailing-spaces": "off",
|
||||
"linebreak-style": "off",
|
||||
"indent": "off",
|
||||
"strict": "off",
|
||||
"no-console": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-shadow": "off",
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"import/no-dynamic-require": "off",
|
||||
"no-underscore-dangle": ["error", { "allowAfterThis": true }],
|
||||
"space-before-function-paren": ["error", "always"],
|
||||
"prefer-destructuring": ["error", { "array": true, "object": true }],
|
||||
"comma-dangle": ["error", "never"],
|
||||
"semi": ["error", "never"]
|
||||
}
|
||||
}
|
76
.github/CODE_OF_CONDUCT.md
vendored
Normal file
76
.github/CODE_OF_CONDUCT.md
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at <louis.grenard@gmail.com>. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
114
.github/CONTRIBUTING.md
vendored
Normal file
114
.github/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
# Contributing
|
||||
|
||||
Thanks a lot for your interest in contributing to Leon! :heart:
|
||||
|
||||
**Leon needs open-source to live**, the more modules he has, the more skillful he becomes.
|
||||
|
||||
**Before submitting your contribution**, please take a moment to review this document.
|
||||
|
||||
Please note we have a [code of conduct](https://github.com/leon-ai/leon/blob/develop/.github/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
|
||||
|
||||
## How You Can Help
|
||||
|
||||
Here are few examples about how you could help on Leon, by:
|
||||
|
||||
- [Creating a new module](https://docs.getleon.ai/packages-modules.html).
|
||||
- [Working on new features](https://roadmap.getleon.ai) (what is in backlog or todo).
|
||||
- [Suggesting new ideas](https://github.com/leon-ai/leon/issues/new/choose).
|
||||
- [Reporting a bug](https://github.com/leon-ai/leon/issues/new?labels=bug&template=BUG.md).
|
||||
- [Improving the documentation](https://github.com/leon-ai/docs.getleon.ai) (translations, typos, better writing, etc.).
|
||||
- [Buying me a fruit juice](https://donate.getleon.ai).
|
||||
|
||||
|
||||
## Pull Requests
|
||||
|
||||
**Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
||||
|
||||
- **Please first discuss** the change you wish to make via [issue](https://github.com/leon-ai/leon/issues),
|
||||
email, or any other method with the owners of this repository before making a change.
|
||||
It might avoid a waste of your time.
|
||||
- The `master` branch is actually used as a snapshot of the latest stable release. **Do not submit your PRs
|
||||
against the `master` branch**.
|
||||
- Ensure your code **respect our coding standards** (cf. [.eslintrc.json](https://github.com/leon-ai/leon/blob/develop/.eslintrc.json)).
|
||||
To do so, you can run:
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
||||
- Make sure your **code passes the tests**. You can run the tests via the following command:
|
||||
|
||||
```sh
|
||||
npm test
|
||||
```
|
||||
|
||||
If you're adding new features to Leon, please include tests.
|
||||
|
||||
## Development Setup
|
||||
|
||||
- Follow the [basic setup](https://github.com/leon-ai/leon/blob/develop/README.md#getting-started).
|
||||
- Then:
|
||||
|
||||
```sh
|
||||
# run development server
|
||||
npm run dev:server
|
||||
|
||||
# run development web app
|
||||
npm run dev:app
|
||||
|
||||
# run the wake word node (optional)
|
||||
npm run wake
|
||||
```
|
||||
|
||||
## Versioning
|
||||
|
||||
- We use [Semantic Versioning](https://semver.org) for releases.
|
||||
- A new Leon module creation increases the MINOR version number of its relevant Leon package.
|
||||
- Each time a MAJOR or MINOR version number of a Leon package is increased, then the MINOR version number of the project should also be increased.
|
||||
- Each time a PATCH version number of a Leon package is increased, then the PATCH version number of the projet should also be increased.
|
||||
|
||||
## Commits
|
||||
|
||||
The commit message guideline is adapted from the [AngularJS Git Commit Guidelines](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines).
|
||||
|
||||
### Types
|
||||
|
||||
Types define which kind of changes you made to the project.
|
||||
|
||||
| Types | Description |
|
||||
| ------------- |-------------|
|
||||
| BREAKING | Changes including breaking changes. |
|
||||
| build | New build version. |
|
||||
| chore | Changes to the build process or auxiliary tools such as changelog generation. No production code change. |
|
||||
| docs | Documentation only changes. |
|
||||
| feat | A new feature. |
|
||||
| fix | A big fix. |
|
||||
| perf | A code change that improves performance. |
|
||||
| refactor | A code change that neither fixes a bug nor adds a feature. |
|
||||
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.). |
|
||||
| test | Adding missing or correcting existing tests. |
|
||||
|
||||
### Scopes
|
||||
|
||||
Scopes define high-level nodes of Leon.
|
||||
|
||||
- web app
|
||||
- server
|
||||
- hotword
|
||||
- package/package_name
|
||||
|
||||
### Examples
|
||||
|
||||
```sh
|
||||
git commit -m "feat(server): awesome new server feature"
|
||||
git commit -m "docs(package/leon): fix spelling"
|
||||
git commit -m "chore: split training script into awesome blocks"
|
||||
git commit -m "style(web app): remove chatbot useless parentheses"
|
||||
```
|
||||
|
||||
## Donate
|
||||
|
||||
You can also contribute by [buying me a fruit juice](https://donate.getleon.ai).
|
||||
|
||||
## Spread the Word
|
||||
|
||||
Use [#LeonAI](https://twitter.com/hashtag/LeonAI) if you tweet about Leon and/or mention [@louistiti_fr](https://twitter.com/louistiti_fr).
|
7
.github/ISSUE_TEMPLATE.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<!--
|
||||
|
||||
Thanks for your interest in Leon! ❤️
|
||||
|
||||
Please check if there is no similar issue before creating this one.
|
||||
|
||||
-->
|
26
.github/ISSUE_TEMPLATE/BUG.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/BUG.md
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
name: 🐞 Bug Report
|
||||
about: Report an unexpected problem or unintended behavior.
|
||||
labels: bug
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for your interest in Leon! ❤️
|
||||
Please check if there is no similar issue before creating this one.
|
||||
-->
|
||||
|
||||
### Specs
|
||||
|
||||
- Leon version:
|
||||
- OS (or browser) version:
|
||||
- Node.js version:
|
||||
- Complete "npm run check" output:
|
||||
- (optional) Leon package version:
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
### How Do We Reproduce?
|
||||
|
||||
### Extra (like a sample repo to reproduce the issue, etc.)
|
22
.github/ISSUE_TEMPLATE/DOCS.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/DOCS.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
name: 📝 Documentation
|
||||
about: Are the docs missing, confusing, etc.? Tell us more about it.
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for your interest in Leon! ❤️
|
||||
If it is related to https://docs.getleon.ai, please open an issue there: https://github.com/leon-ai/docs.getleon.ai/issues.
|
||||
Please check if there is no similar issue before creating this one.
|
||||
|
||||
Please place an x (no spaces - [x]) in all [ ] that apply.
|
||||
-->
|
||||
|
||||
### Documentation Is:
|
||||
- [ ] Missing
|
||||
- [ ] Needed
|
||||
- [ ] Confusing
|
||||
- [ ] Not Sure?
|
||||
|
||||
### Explanation
|
||||
|
||||
### Proposal
|
14
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: ✨ Feature Request
|
||||
about: Suggest a new feature idea.
|
||||
labels: feature request
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for your interest in Leon! ❤️
|
||||
Please check if there is no similar issue before creating this one.
|
||||
-->
|
||||
|
||||
### Feature Use Case
|
||||
|
||||
### Feature Proposal
|
16
.github/ISSUE_TEMPLATE/IMPROVEMENT.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/IMPROVEMENT.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
name: 🔧 Improvement
|
||||
about: Suggest an idea which is not a feature.
|
||||
labels: improvement
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for your interest in Leon! ❤️
|
||||
Please check if there is no similar issue before creating this one.
|
||||
-->
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
### Proposal
|
14
.github/ISSUE_TEMPLATE/QUESTION.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/QUESTION.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: ❓ Question
|
||||
about: Ask a question about Leon.
|
||||
labels: question
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for your interest in Leon! ❤️
|
||||
Please check if there is no similar issue before creating this one.
|
||||
|
||||
Please ask one question per issue.
|
||||
-->
|
||||
|
||||
### Question
|
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<!--
|
||||
|
||||
Thanks a lot for your interest in contributing to Leon! :heart:
|
||||
|
||||
Please first discuss the change you wish to make via issue,
|
||||
email, or any other method with the owners of this repository before making a change.
|
||||
It might avoid a waste of your time.
|
||||
|
||||
Before submitting your contribution, please take a moment to review this document:
|
||||
https://github.com/leon-ai/leon/blob/develop/.github/CONTRIBUTING.md
|
||||
|
||||
Please place an x (no spaces - [x]) in all [ ] that apply.
|
||||
|
||||
-->
|
||||
|
||||
### What type of change does this PR introduce?
|
||||
- [ ] Bugfix
|
||||
- [ ] Feature
|
||||
- [ ] Refactor
|
||||
- [ ] Documentation
|
||||
- [ ] Not Sure?
|
||||
|
||||
### Does this PR introduce breaking changes?
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
|
||||
### List any relevant issue numbers:
|
||||
|
||||
### Description:
|
||||
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
__pycache__/
|
||||
.idea/
|
||||
**/dist/
|
||||
**/node_modules/
|
||||
test/coverage/
|
||||
**/tmp/*
|
||||
bridges/python/.venv/*
|
||||
downloads/*
|
||||
logs/*
|
||||
server/src/config/**/*.json
|
||||
bin/deepspeech/*
|
||||
bin/flite/*
|
||||
|
||||
*.pyc
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
debug.log
|
||||
.env
|
||||
!**/.gitkeep
|
||||
!bridges/python/.venv/.gitkeep
|
||||
!**/*.sample*
|
||||
packages/**/config/config.json
|
||||
packages/**/data/db/*.json
|
||||
server/src/data/expressions/classifier.json
|
||||
app/js/main.js
|
||||
package.json.backup
|
335
CHANGELOG.md
Normal file
335
CHANGELOG.md
Normal file
@ -0,0 +1,335 @@
|
||||
# [1.0.0-beta.0](https://github.com/Louistiti/leon/compare/https://github.com/Louistiti/leon.git...v1.0.0-beta.0) (2019-02-10)
|
||||
### BREAKING CHANGES
|
||||
- new CI
|
||||
([9dac4c83](https://github.com/Louistiti/leon/commit/9dac4c83759e56dc5f69ddff895ba1bc6034b442))
|
||||
- new CI
|
||||
([705f81c4](https://github.com/Louistiti/leon/commit/705f81c41588f6dd7ca657ffa2007a04375740a6))
|
||||
- rename `*-sample*` files to `*.sample*`
|
||||
([7e3ab427](https://github.com/Louistiti/leon/commit/7e3ab427b6150abad8f2ccdc24228ef2ab6d94d2))
|
||||
- get rid of gulp.js
|
||||
([c5676cf2](https://github.com/Louistiti/leon/commit/c5676cf271473d083b377897ac928c7c68c9e831))
|
||||
|
||||
- **server:**
|
||||
- new Watson STT
|
||||
([deb854b2](https://github.com/Louistiti/leon/commit/deb854b2d6e80b32e009b13b3e3cc067f05ae0bc))
|
||||
- new Watson TTS
|
||||
([a5a6d72b](https://github.com/Louistiti/leon/commit/a5a6d72bda2b0b35b03bbbe2c09555b55f605d9e))
|
||||
- switch NLP to NLU
|
||||
([32fe88b1](https://github.com/Louistiti/leon/commit/32fe88b1ef26c6ab73066c76c8fc3cd5d2b7b1a4))
|
||||
- binary TTS and STT structure
|
||||
([11689e88](https://github.com/Louistiti/leon/commit/11689e88627dfd02e961b7f3bfaa0e5ff2c0333d))
|
||||
### Features
|
||||
- preinstall script
|
||||
([0644296b](https://github.com/Louistiti/leon/commit/0644296b10e857c6811555ab30bad6236d124e60))
|
||||
- preinstall script
|
||||
([6793c9f6](https://github.com/Louistiti/leon/commit/6793c9f61ba323b9ee453d5992a8115e41f54131))
|
||||
- preinstall script
|
||||
([a53be750](https://github.com/Louistiti/leon/commit/a53be7504c6c8ba3eee5966d2190190733bde069))
|
||||
- preinstall script
|
||||
([82299099](https://github.com/Louistiti/leon/commit/82299099600ca7929534bcca4243be01fae1da73))
|
||||
- preinstall script
|
||||
([1b0b3e9e](https://github.com/Louistiti/leon/commit/1b0b3e9e33fe8fec0415e1985303610aa002ce3a))
|
||||
- preinstall script
|
||||
([231d68d6](https://github.com/Louistiti/leon/commit/231d68d6c7d0ea366784cfd28da95f3a9012cfd5))
|
||||
- preinstall script
|
||||
([fb45d9ed](https://github.com/Louistiti/leon/commit/fb45d9ed744d0c473fab7f79e90c25d6723d9b99))
|
||||
- check script
|
||||
([e545ac58](https://github.com/Louistiti/leon/commit/e545ac5847f6e38649a494730b99e9a002015470))
|
||||
- chatbot visual almost done for the v1
|
||||
([94a2f557](https://github.com/Louistiti/leon/commit/94a2f55757bf06487a2fbd8c84c1eff677568516))
|
||||
|
||||
- **package/leon:**
|
||||
- add partner assistant module
|
||||
([794a4d73](https://github.com/Louistiti/leon/commit/794a4d73957cd6b5d7d434b8727426e8a31d0618))
|
||||
- add sentence to the whoami module
|
||||
([a241cdc0](https://github.com/Louistiti/leon/commit/a241cdc0bf04515b18bbc40ddb117e092851afd2))
|
||||
- **client:**
|
||||
voice detection
|
||||
([eec7fc8d](https://github.com/Louistiti/leon/commit/eec7fc8d8f3e28cfd2d844c4319239d88609c77a))
|
||||
- **devapp:**
|
||||
disable mic when the STT is disabled
|
||||
([e0bf1163](https://github.com/Louistiti/leon/commit/e0bf116360a5b3b43618c04b352cd97f70a161b2))
|
||||
- **hotword:**
|
||||
server and client ready
|
||||
([a5a8f932](https://github.com/Louistiti/leon/commit/a5a8f9321daff80d52c5a2454281317acb61db7e))
|
||||
- **hotword + after-speech:**
|
||||
done
|
||||
([db813296](https://github.com/Louistiti/leon/commit/db813296dea8c7f702d186762758bdfe2fad0251))
|
||||
- **module:**
|
||||
- Bye done
|
||||
([e178de05](https://github.com/Louistiti/leon/commit/e178de0513f5867257621a50b5dabc36790fc64f))
|
||||
- Random Number done + Meaning of Life done + Welcome done
|
||||
([5a3b3f75](https://github.com/Louistiti/leon/commit/5a3b3f75e59395ef078cfa3fceca3d89fd364cfe))
|
||||
- Greeting done
|
||||
([8a6fa9c5](https://github.com/Louistiti/leon/commit/8a6fa9c52cd1c82c46ed21c4f4af83f615da4bc4))
|
||||
- Joke done
|
||||
([367318f7](https://github.com/Louistiti/leon/commit/367318f75101822409f0f00be315f805340a3fe4))
|
||||
- **core:**
|
||||
- NLP fallback + confidence for each language + French translations written
|
||||
([d8004d12](https://github.com/Louistiti/leon/commit/d8004d1217d146de825ae356d97b97b2d511b192))
|
||||
- STT + TTS translations architecture
|
||||
([447efd21](https://github.com/Louistiti/leon/commit/447efd218af96a9c472cbd059ac8813a756640d1))
|
||||
- **stt:**
|
||||
- Google Cloud STT implemented
|
||||
([216765cc](https://github.com/Louistiti/leon/commit/216765cc42f2ec683233f093152f3ce8b048508d))
|
||||
- ASR class created + delete audios file after STT job
|
||||
([69b1fcce](https://github.com/Louistiti/leon/commit/69b1fcce77786cf64aea1af0e643ab0dd7298550))
|
||||
- done + need to prepare init models thanks to a thread
|
||||
([46d36990](https://github.com/Louistiti/leon/commit/46d36990398bc2179658efb00ffbbc38cc18a735))
|
||||
- client send stream to server + server convert stream to a WAVE file
|
||||
([67ceb99a](https://github.com/Louistiti/leon/commit/67ceb99a9c2620f4ab4e8510c6ef37eb2723d428))
|
||||
- **stt and tts:**
|
||||
Watson implemented
|
||||
([3dae3d68](https://github.com/Louistiti/leon/commit/3dae3d6811febf0c25032752a07c9fcd26d9580e))
|
||||
- **test:**
|
||||
this is a test. Close #1
|
||||
([5efe707d](https://github.com/Louistiti/leon/commit/5efe707df7e63c8c12fd3ce54d31b858da75541e))
|
||||
- **tts:**
|
||||
- Amazon Polly implemented
|
||||
([cd5dbe7a](https://github.com/Louistiti/leon/commit/cd5dbe7a0fa9cd958d4c355db44ee3f82a465b16))
|
||||
- Google Cloud TTS implemented
|
||||
([eb3e18e8](https://github.com/Louistiti/leon/commit/eb3e18e82f51f59eb5c7c9fb3afab68d39c04939))
|
||||
- done
|
||||
([2e5d3f18](https://github.com/Louistiti/leon/commit/2e5d3f18692f8a45304d9b3d1c0689fd4124c9f0))
|
||||
- architecture done + need to delete audio files + forward buffer to the client
|
||||
([85664eef](https://github.com/Louistiti/leon/commit/85664eefc1839dfc946dbc17a55a96119089c6ac))
|
||||
- **web app:**
|
||||
- add favicon
|
||||
([6d0ae10d](https://github.com/Louistiti/leon/commit/6d0ae10ddb8ba478ad9218a1c23fa686b55555c9))
|
||||
- avoid N - 1 duplicate to browse commands history
|
||||
([930eac09](https://github.com/Louistiti/leon/commit/930eac094a61d16013ab4fc320e2a28b853c6f38))
|
||||
- chatbot done
|
||||
([520bef6d](https://github.com/Louistiti/leon/commit/520bef6d8e8ab51f0c2478e7b00d1dd34d03ee24))
|
||||
### Bug Fixes
|
||||
- Python output switch key to code
|
||||
([8a7d6124](https://github.com/Louistiti/leon/commit/8a7d6124aeac533f84a23d21b60f6ab51be3b848))
|
||||
- setup-stt wget
|
||||
([c1d7a682](https://github.com/Louistiti/leon/commit/c1d7a6827128b97645a2ab610c0e6ae1a1b1188c))
|
||||
- dev build app
|
||||
([53681a55](https://github.com/Louistiti/leon/commit/53681a55aee8af803e8a4cb4ba1ea87f7823121e))
|
||||
- Windows setup
|
||||
([7609a509](https://github.com/Louistiti/leon/commit/7609a5092a2ce1396387288c6c2df15a6ed9328b))
|
||||
- setup offline
|
||||
([c74134b4](https://github.com/Louistiti/leon/commit/c74134b46d2e15d66599ddb0b0dee63f8fc2faed))
|
||||
- offline setup on Linux
|
||||
([3278aad6](https://github.com/Louistiti/leon/commit/3278aad6c4b412b5d523482a0e4b4c8ba82ed006))
|
||||
- build script
|
||||
([732f9027](https://github.com/Louistiti/leon/commit/732f902755699e5dbb8bc03296f6f326cde83dfe))
|
||||
- setup env vars
|
||||
([3606edc4](https://github.com/Louistiti/leon/commit/3606edc4934636c81d74ddf6c42d38b76b75e7e8))
|
||||
- .env LANG and LC_ALL
|
||||
([ff652bb5](https://github.com/Louistiti/leon/commit/ff652bb5193d138532901f1eb5fbe63510fb5fae))
|
||||
- brain TTS init when enabled
|
||||
([3697c89a](https://github.com/Louistiti/leon/commit/3697c89a3669caee75967152433b3066bd310aa3))
|
||||
- multiple things
|
||||
([42bdb88a](https://github.com/Louistiti/leon/commit/42bdb88a68f4e6ab4d48583f6ba934b07f61bb52))
|
||||
- setup python packages checking
|
||||
([843a3012](https://github.com/Louistiti/leon/commit/843a3012bfa7864dd34ea513d400a87b3b4e1297))
|
||||
- Python version requirements
|
||||
([acebd80b](https://github.com/Louistiti/leon/commit/acebd80b0c99aa703218048d94191121175e9833))
|
||||
- chore training
|
||||
([68d559a3](https://github.com/Louistiti/leon/commit/68d559a3a17a9d31700534036af23aaa1c98c08e))
|
||||
- CHANGELOG generator
|
||||
([574847b5](https://github.com/Louistiti/leon/commit/574847b5bb7cbadad577f522aeac0546042d354b))
|
||||
- this is a fix
|
||||
([3e62378e](https://github.com/Louistiti/leon/commit/3e62378eff270b6beb7fa4dc4bb368f3859d806b))
|
||||
|
||||
- **.gitignore:**
|
||||
.json TinyDB
|
||||
([13fdcd63](https://github.com/Louistiti/leon/commit/13fdcd6307115c1409dd1389d27bbe5d6b213d04))
|
||||
- **changelog:**
|
||||
happy to fix that bug
|
||||
([276a78d1](https://github.com/Louistiti/leon/commit/276a78d17e2c37371412b94e1b19971b4378a099))
|
||||
- **config:**
|
||||
voice samples
|
||||
([c497c685](https://github.com/Louistiti/leon/commit/c497c68560525bc718be83c41edb45c5cebbb75b))
|
||||
- **devapp:**
|
||||
do not send query while writing
|
||||
([8344d861](https://github.com/Louistiti/leon/commit/8344d8613e4fe737ab187a4a74f61d038fb8e5da))
|
||||
- **package/leon:**
|
||||
- "à bon escient"
|
||||
([41868833](https://github.com/Louistiti/leon/commit/41868833e1659c9b4f6752b4ed190acaadff3c09))
|
||||
- Siri answer
|
||||
([a9a2d469](https://github.com/Louistiti/leon/commit/a9a2d469bb21b7f10c805b77f1efa8905a5b3d67))
|
||||
- **server:**
|
||||
- ASR FFmpeg mono channel
|
||||
([49c5abfc](https://github.com/Louistiti/leon/commit/49c5abfc7c56f136ff4ab12e010b1b7ece750163))
|
||||
- brain execution was stopping after the first query
|
||||
([9da0c9a9](https://github.com/Louistiti/leon/commit/9da0c9a9c0a9de5a2d3825b773a8d26335eb71ef))
|
||||
- **setup:**
|
||||
core files path
|
||||
([6a3fb9b0](https://github.com/Louistiti/leon/commit/6a3fb9b08cfa75556181c742a41eb5f05512e938))
|
||||
- **test:**
|
||||
- latest test
|
||||
([3bd2e95a](https://github.com/Louistiti/leon/commit/3bd2e95afabde3f549110681a5497183ea98b0dc))
|
||||
- this is another fix
|
||||
([9de09067](https://github.com/Louistiti/leon/commit/9de09067d4ddeb840e8eac4e91b0f4990025702c))
|
||||
- **web app:**
|
||||
allow init even when mic is not allowed
|
||||
([da469d9d](https://github.com/Louistiti/leon/commit/da469d9df34920b6c542d75d9046c7fdedf9bf0b))
|
||||
### Performance Improvements
|
||||
- improve for loop
|
||||
([f3c64495](https://github.com/Louistiti/leon/commit/f3c644956d724b0ef684cd5a5314bfd25c9bfcb7))
|
||||
|
||||
### Documentation Changes
|
||||
- update logo size
|
||||
([df813c49](https://github.com/Louistiti/leon/commit/df813c4958bb7b0febf4710595ad7d2d1dac4ad8))
|
||||
- README edit video preview
|
||||
([b77f86f4](https://github.com/Louistiti/leon/commit/b77f86f4a09fd1f55e2bca8125d7fc034aa4914a))
|
||||
- README video
|
||||
([41761226](https://github.com/Louistiti/leon/commit/417612264fdfb5280f2b7567788501304de45966))
|
||||
- CONTRIBUTING adding roadmap
|
||||
([fd99683f](https://github.com/Louistiti/leon/commit/fd99683ff1bed00880832d5467aa2613b8ebd4ca))
|
||||
- add Twitter in the README "Stay Tuned" section
|
||||
([c6dfef7a](https://github.com/Louistiti/leon/commit/c6dfef7a7f56381064c8672f11ece308e810be29))
|
||||
- badges updated
|
||||
([f3dcb203](https://github.com/Louistiti/leon/commit/f3dcb203d14f49c0dac5d9d11b663a4908e09e7b))
|
||||
- typo fix
|
||||
([cae01084](https://github.com/Louistiti/leon/commit/cae01084e3a4611c32b83ab08faada51f841d808))
|
||||
- improve README
|
||||
([087a02bf](https://github.com/Louistiti/leon/commit/087a02bfa76892986c7e173fbbb703ef8fe70513))
|
||||
- supported OS
|
||||
([91353dee](https://github.com/Louistiti/leon/commit/91353deef673d39b9dce6fb51d0d7862edf9362a))
|
||||
- improve README
|
||||
([6c201e27](https://github.com/Louistiti/leon/commit/6c201e2709567f510f6a5fb93d34715f1f9f682b))
|
||||
- improve README
|
||||
([ec1406c2](https://github.com/Louistiti/leon/commit/ec1406c215245a7761c89de8256759c8017c103f))
|
||||
- improve README
|
||||
([0cdc683e](https://github.com/Louistiti/leon/commit/0cdc683ec65c32907308926e703915405f723233))
|
||||
- CONTRIBUTING improvement
|
||||
([7dba9928](https://github.com/Louistiti/leon/commit/7dba9928ce8e2df2b7dc26b3ac2671779edb23e3))
|
||||
- contributing improvement
|
||||
([6716585b](https://github.com/Louistiti/leon/commit/6716585b5250b1309d796e36ee2d865b736bd17f))
|
||||
- italic README catchphrase
|
||||
([dad0c268](https://github.com/Louistiti/leon/commit/dad0c2681a82432ee292b145f400befd5f537a07))
|
||||
- tiny README change
|
||||
([633f5f29](https://github.com/Louistiti/leon/commit/633f5f29e5b32f565cb6c7d53ec309aba77b0121))
|
||||
- improve README
|
||||
([4ee74263](https://github.com/Louistiti/leon/commit/4ee74263fd52028cd1a12479990531fe1b9edba4))
|
||||
- improve README
|
||||
([2541e466](https://github.com/Louistiti/leon/commit/2541e46677556427f49e484cbdf54496859da24e))
|
||||
- improve README
|
||||
([d469c9e5](https://github.com/Louistiti/leon/commit/d469c9e5777819afeec671b2951d360375891164))
|
||||
- edit donation link
|
||||
([c1b3e45e](https://github.com/Louistiti/leon/commit/c1b3e45e3a397e424d42d59348bf8b3425698858))
|
||||
- adjust few things
|
||||
([abf3bbc5](https://github.com/Louistiti/leon/commit/abf3bbc5a70c4da3007b648428713757f9568e4a))
|
||||
- README or to OR
|
||||
([7d10ef26](https://github.com/Louistiti/leon/commit/7d10ef26ba24d59fc1c0d6b041d1d14bbed7f9e1))
|
||||
- fix
|
||||
([22b1ab5b](https://github.com/Louistiti/leon/commit/22b1ab5bc6a468d7ffe23e1857acca8c9301ef92))
|
||||
- fix
|
||||
([11a6df36](https://github.com/Louistiti/leon/commit/11a6df36fa9d030cac063a15057a7463eca0684f))
|
||||
- docs.getleon.ai redirect
|
||||
([bba41cd9](https://github.com/Louistiti/leon/commit/bba41cd97d41858781185f5cd5866dde3f2cb754))
|
||||
- sentence improvement
|
||||
([18720175](https://github.com/Louistiti/leon/commit/1872017535c36c16ca59ca2ee9c378244159fd5c))
|
||||
- improve commit message description
|
||||
([3d9698bf](https://github.com/Louistiti/leon/commit/3d9698bffc68413c7c429725eae45cf3edecc1db))
|
||||
- README.md done
|
||||
([300b1538](https://github.com/Louistiti/leon/commit/300b15382d0fb7ecf9c5275304c0798f8eaadb5c))
|
||||
- README
|
||||
([105965f3](https://github.com/Louistiti/leon/commit/105965f3ab65cfc7157e66d07fff4ba0065b863b))
|
||||
- README
|
||||
([6b089d16](https://github.com/Louistiti/leon/commit/6b089d168a80ce197da1e38f958a3df802d72f6b))
|
||||
- README
|
||||
([1e4eb629](https://github.com/Louistiti/leon/commit/1e4eb629924290e2b47c4e078e8085faeea9149d))
|
||||
- README
|
||||
([e8d6039f](https://github.com/Louistiti/leon/commit/e8d6039f1ef073599c847ef0cc5fb43c65505a89))
|
||||
- README
|
||||
([d999bdc3](https://github.com/Louistiti/leon/commit/d999bdc385768f2d87427ba1cc229aa71c0855f2))
|
||||
- QUESTION.md quick fix
|
||||
([05c74653](https://github.com/Louistiti/leon/commit/05c74653fdbc86173f8042dd17f1f74f048a3c20))
|
||||
- QUESTION.md quick fix
|
||||
([6a94f9da](https://github.com/Louistiti/leon/commit/6a94f9da691217e9590a78ac53622db50f953259))
|
||||
- ISSUE_TEMPLATE/QUESTION.md
|
||||
([6f97614b](https://github.com/Louistiti/leon/commit/6f97614b6d16c4ebaa0561393efb996519dc2426))
|
||||
- ISSUE_TEMPLATE/DOCS.md
|
||||
([ba4b83f1](https://github.com/Louistiti/leon/commit/ba4b83f1b0ac514648294ecfd466d4188bc8d5d0))
|
||||
- ISSUE_TEMPLATE/FEATURE_REQUEST.mdt and ISSUE_TEMPLATE/IMPROVEMENT.md
|
||||
([f48ad692](https://github.com/Louistiti/leon/commit/f48ad692d264f84345631f3f79cea1fac5a5748b))
|
||||
- delete tmp BUG.md
|
||||
([3e76cf29](https://github.com/Louistiti/leon/commit/3e76cf29dcb95e263339850127b4ef7590feb762))
|
||||
- ISSUE_TEMPLATE/BUG.md
|
||||
([efcbdffc](https://github.com/Louistiti/leon/commit/efcbdffc026608302a1bbfce160bf0d995a356ca))
|
||||
- README.md quick fix
|
||||
([c9414490](https://github.com/Louistiti/leon/commit/c9414490c9956e35ae466973d4fad92f87053561))
|
||||
- README.md quick fix
|
||||
([8f242248](https://github.com/Louistiti/leon/commit/8f2422481e5eabc151f6f8adea04772dc6045669))
|
||||
- README.md skeleton
|
||||
([6ab10817](https://github.com/Louistiti/leon/commit/6ab108179c90dc06f71a7a5acc9e6d7f6f7c4539))
|
||||
- ISSUE_TEMPLATE.md quick fix
|
||||
([e2966435](https://github.com/Louistiti/leon/commit/e296643598dc10e4afb75472e71f300aaf16ca73))
|
||||
- ISSUE_TEMPLATE.md done
|
||||
([e6149798](https://github.com/Louistiti/leon/commit/e6149798b0021bacf9ad8a0ed1d2ed47c489098f))
|
||||
- ISSUE_TEMPLATE.md heart
|
||||
([180a329c](https://github.com/Louistiti/leon/commit/180a329c71edb55437d59d3753974b60323903bc))
|
||||
- ISSUE_TEMPLATE.md tmp
|
||||
([b04b1acc](https://github.com/Louistiti/leon/commit/b04b1acc3558b6193c95a0d26dc664519fdbeac3))
|
||||
- PULL_REQUEST_TEMPLATE.md
|
||||
([25264a80](https://github.com/Louistiti/leon/commit/25264a808900d0713418ec0b2d440951052e01fc))
|
||||
- finale CONTRIBUTING.md
|
||||
([776088fc](https://github.com/Louistiti/leon/commit/776088fc7f2d106b12b2a0df0fd9fcec66568651))
|
||||
- quick fix
|
||||
([51742875](https://github.com/Louistiti/leon/commit/51742875e50b9513415beabc5dd0ef926a125628))
|
||||
- quick fix
|
||||
([b21e8553](https://github.com/Louistiti/leon/commit/b21e8553a01c1088d4450ff19f192b602675d66d))
|
||||
- add heart to CONTRIBUTING.md
|
||||
([3e818c6e](https://github.com/Louistiti/leon/commit/3e818c6ec309cabab5eee220f0dbd20b6e77a28a))
|
||||
- CONTRIBUTING.md
|
||||
([9c93fdf0](https://github.com/Louistiti/leon/commit/9c93fdf02d7e4543e01164fae3f7a5bba38e837f))
|
||||
- Code of Conduct latest version
|
||||
([e09c0785](https://github.com/Louistiti/leon/commit/e09c0785274774e95802780a3fc183a39230bde1))
|
||||
- Code of Conduct
|
||||
([b170adb8](https://github.com/Louistiti/leon/commit/b170adb8f3183cab2dbc83dd0850eec03764776d))
|
||||
- small changes on README.md and LICENSE.md
|
||||
([45650d36](https://github.com/Louistiti/leon/commit/45650d3602606571f27e73aed9955871ec8fb5b2))
|
||||
- clean CHANGELOG
|
||||
([5d32522b](https://github.com/Louistiti/leon/commit/5d32522b4904264de074ff6e063b28c72f746c02))
|
||||
- README PRs welcome badge
|
||||
([dee8eb99](https://github.com/Louistiti/leon/commit/dee8eb99fc8fcd181cdf6799120448a38e958fdf))
|
||||
- README PRs welcome badge
|
||||
([f141153e](https://github.com/Louistiti/leon/commit/f141153e02be33f56a5b4e95f4f260a07c078963))
|
||||
- README badges
|
||||
([75b6abf7](https://github.com/Louistiti/leon/commit/75b6abf783f32fde5ca4df5e329046da3701edac))
|
||||
- update README
|
||||
([2ad16984](https://github.com/Louistiti/leon/commit/2ad16984c62c3190efd3c1c0c66709da047246a1))
|
||||
- license updated
|
||||
([b5c87cfb](https://github.com/Louistiti/leon/commit/b5c87cfb4da79fc492c14f048f44ce85ba6526e0))
|
||||
- this is a test
|
||||
([e54758fe](https://github.com/Louistiti/leon/commit/e54758fe63a15e70cd9618279ec577cb99d28294))
|
||||
- docs(CHANGELOG.md)
|
||||
([e289a74c](https://github.com/Louistiti/leon/commit/e289a74ccca82ee20b8b7e453282d3fc61dd1e0f))
|
||||
|
||||
- **changelog:**
|
||||
- reset
|
||||
([d9739c81](https://github.com/Louistiti/leon/commit/d9739c81d204d317d19dd3c27311e7861bb0a90a))
|
||||
- here is a new test
|
||||
([2aabbf26](https://github.com/Louistiti/leon/commit/2aabbf262b4900287aa324098d3a7cf6020ab8fa))
|
||||
- add new chore
|
||||
([8eaa9c75](https://github.com/Louistiti/leon/commit/8eaa9c757929ec648720c05866c23a0aa9548a8c))
|
||||
- just few tests
|
||||
([0948adbe](https://github.com/Louistiti/leon/commit/0948adbeba05e71eaa0f17dee57b8a62b216826f))
|
||||
- **package.json:**
|
||||
homepage URL
|
||||
([d82f34d0](https://github.com/Louistiti/leon/commit/d82f34d069ac7c14ddecc07dad1689b752c3fb61))
|
||||
- **package/checker:**
|
||||
README
|
||||
([6ddedd24](https://github.com/Louistiti/leon/commit/6ddedd24a5f10a594ac402bb256f7feb01f70f16))
|
||||
- **package/leon:**
|
||||
README
|
||||
([3cde3273](https://github.com/Louistiti/leon/commit/3cde3273f6b0fa207d0bcd4b85040843eec4f3ba))
|
||||
- **package/videodownloader:**
|
||||
- quick fix
|
||||
([bf16c2c6](https://github.com/Louistiti/leon/commit/bf16c2c64cdd0b596762761e86fb9917efef22f3))
|
||||
- README
|
||||
([3ac3f47d](https://github.com/Louistiti/leon/commit/3ac3f47d4df716be8025096bd5fd8e4cf9c5393a))
|
||||
- **readme:**
|
||||
- specify recommended virtual env
|
||||
([d98cfb72](https://github.com/Louistiti/leon/commit/d98cfb72589fb257015e4eabc182b6ae1b497d85))
|
||||
- another test
|
||||
([cae8cf8f](https://github.com/Louistiti/leon/commit/cae8cf8f46ee25a06ae87c878bdfd39e5efc15f8))
|
||||
- alphabetical testing
|
||||
([6fcc867d](https://github.com/Louistiti/leon/commit/6fcc867dbcec1b34239d9d4d73d0fe26bc8f57ec))
|
||||
|
||||
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-present, Louis Grenard <louis.grenard@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
130
README.md
Normal file
130
README.md
Normal file
@ -0,0 +1,130 @@
|
||||
<p align="center">
|
||||
<a href="https://getleon.ai"><img width="96" src="https://getleon.ai/img/logo.svg"></a><br><br>
|
||||
<a href="https://www.youtube.com/watch?v=p7GRGiicO1c"><img width="512" src="https://getleon.ai/img/1.0.0-beta.0_preview_en.png"></a><br>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Leon</h1>
|
||||
|
||||
*<p align="center">Your open-source personal assistant.</p>*
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/leon-ai/leon/blob/develop/LICENSE.md"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat"/></a>
|
||||
<a href="https://circleci.com/gh/leon-ai/leon/tree/develop"><img src="https://img.shields.io/circleci/project/github/leon-ai/leon.svg?style=flat"/></a>
|
||||
<a href="https://github.com/leon-ai/leon/blob/develop/.github/CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://getleon.ai">Website</a> ::
|
||||
<a href="https://docs.getleon.ai">Documentation</a> ::
|
||||
<a href="https://roadmap.getleon.ai">Roadmap</a> ::
|
||||
<a href="https://github.com/leon-ai/leon/blob/develop/.github/CONTRIBUTING.md">Contributing</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Leon is an **open-source personal assistant** who can live **on your server**.
|
||||
|
||||
He **does stuff** when you **ask for it**.
|
||||
|
||||
You can **talk to him** and he can **talk to you**.
|
||||
You can also **text him** and he can also **text you**.
|
||||
If you want to, Leon can communicate with you by being **offline to protect your privacy**.
|
||||
|
||||
### Why?
|
||||
> 1. If you are a developer (or not), you may want to build many things that could help in your daily life.
|
||||
> Instead of building a dedicated project for each of those ideas, Leon can help you with his
|
||||
> packages/modules (skills) structure.
|
||||
> 2. With this generic structure, everyone can create his own modules and share them with others.
|
||||
> Therefore there is only one core (to govern all of them).
|
||||
> 3. Leon uses AI concepts, which is cool.
|
||||
> 4. Privacy matters, you can configure Leon to talk with him offline. You can already text with him without any third party services.
|
||||
> 5. Open-source is great.
|
||||
|
||||
### What is this repository for?
|
||||
> This repository contains the following nodes of Leon:
|
||||
> - The server
|
||||
> - The packages/modules
|
||||
> - The web app
|
||||
> - The hotword node
|
||||
|
||||
Sounds good for you? Then let's get started!
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Node.js](https://nodejs.org/) >= 10
|
||||
- npm >= 5
|
||||
- [Python](https://www.python.org/downloads/) 3.6.x
|
||||
- [Pipenv](https://docs.pipenv.org)
|
||||
- Supported OSes: Linux, macOS and Windows
|
||||
|
||||
To install these prerequisites, you can follow the [How To section](https://docs.getleon.ai/how-to/) of the documentation.
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
# Clone the repository (stable branch)
|
||||
git clone -b master https://github.com/leon-ai/leon.git leon
|
||||
# OR download the latest release at: https://github.com/leon-ai/leon/releases/latest
|
||||
|
||||
# Go to the project root
|
||||
cd leon
|
||||
|
||||
# Install
|
||||
npm install
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
# Check the setup went well
|
||||
npm run check
|
||||
|
||||
# Build
|
||||
npm run build
|
||||
|
||||
# Run
|
||||
npm start
|
||||
|
||||
# Go to http://localhost:1337
|
||||
# Hooray! Leon is running
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
For full documentation, visit [docs.getleon.ai](https://docs.getleon.ai).
|
||||
|
||||
## Roadmap
|
||||
|
||||
To know what is going on, follow [roadmap.getleon.ai](https://roadmap.getleon.ai).
|
||||
|
||||
## Contributing
|
||||
|
||||
If you have an idea about improving Leon, do not hesitate.
|
||||
|
||||
**Leon needs open-source to live**, the more modules he has, the more skillful he becomes.
|
||||
|
||||
## Stay Tuned
|
||||
- [Newsletter](https://getleon.ai)
|
||||
- [Blog](https://blog.getleon.ai)
|
||||
- [GitHub issues](https://github.com/leon-ai/leon/issues)
|
||||
- [Twitter](https://twitter.com/louistiti_fr)
|
||||
- [#LeonAI](https://twitter.com/hashtag/LeonAI)
|
||||
|
||||
## Author
|
||||
**Louis Grenard** ([@louistiti_fr](https://twitter.com/louistiti_fr))
|
||||
|
||||
## Donate
|
||||
|
||||
You can also contribute by [buying me a fruit juice](https://donate.getleon.ai).
|
||||
|
||||
## License
|
||||
[MIT License](https://github.com/leon-ai/leon/blob/develop/LICENSE.md)
|
||||
|
||||
Copyright (c) 2019-present, Louis Grenard <louis.grenard@gmail.com>
|
||||
|
||||
## Cheers!
|
||||
![Cheers!](https://assets-cdn.github.com/images/icons/emoji/unicode/1f37b.png?v6 "Cheers!")
|
289
app/css/style.css
Normal file
289
app/css/style.css
Normal file
@ -0,0 +1,289 @@
|
||||
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,600,700,800);
|
||||
|
||||
html, body, div, span, applet, object, iframes,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, sub, sup, tt, var,
|
||||
u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #FFF;
|
||||
background-color: #151718;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
}
|
||||
body > * {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
body.settingup > * {
|
||||
opacity: 0;
|
||||
}
|
||||
body.settingup::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-color: #777;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 50%;
|
||||
animation: scaleout .6s infinite ease-in-out;
|
||||
}
|
||||
@keyframes scaleout {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1.0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
position: absolute;
|
||||
width: 63%;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
input {
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-bottom: 2px solid #FFF;
|
||||
background: none;
|
||||
font-weight: 400;
|
||||
font-size: 4em;
|
||||
padding-right: 39px;
|
||||
}
|
||||
|
||||
small {
|
||||
color: #FFF;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#logo {
|
||||
background: no-repeat url(../img/logo.svg);
|
||||
margin: 0 auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
#feed {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 10%;
|
||||
height: 50%;
|
||||
overflow-y: auto;
|
||||
border: 2px solid #FFF;
|
||||
border-radius: 12px;
|
||||
}
|
||||
#feed::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
#feed::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(255, 255, 255, .2);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
#no-bubble {
|
||||
margin-top: 64px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#is-typing {
|
||||
position: absolute;
|
||||
top: 59%;
|
||||
padding: 0 8px;
|
||||
opacity: 0;
|
||||
margin-top: 20px;
|
||||
transition: opacity .3s;
|
||||
}
|
||||
#is-typing.on {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#is-typing .circle {
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #FFF;
|
||||
transform: scale(1);
|
||||
}
|
||||
#is-typing .circle:nth-child(1) {
|
||||
animation: typing .2s linear infinite alternate;
|
||||
background-color: #0071F0;
|
||||
}
|
||||
#is-typing .circle:nth-child(2) {
|
||||
animation: typing .2s .2s linear infinite alternate;
|
||||
background-color: #FFF;
|
||||
}
|
||||
#is-typing .circle:nth-child(3) {
|
||||
animation: typing .2s linear infinite alternate;
|
||||
background-color: #EC297A;
|
||||
}
|
||||
@keyframes typing {
|
||||
100% {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
}
|
||||
|
||||
.bubble-container {
|
||||
padding: 6px;
|
||||
}
|
||||
.bubble-container.me {
|
||||
text-align: right;
|
||||
}
|
||||
.bubble-container.leon {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
padding: 6px 12px;
|
||||
border-radius: 16px;
|
||||
display: inline-block;
|
||||
max-width: 60%;
|
||||
word-break: break-word;
|
||||
text-align: left;
|
||||
opacity: 0;
|
||||
animation: fadeIn .2s ease-in forwards;
|
||||
}
|
||||
#feed .me .bubble {
|
||||
background-color: #1C75DB;
|
||||
color: #FFF;
|
||||
right: 0;
|
||||
}
|
||||
#feed .leon .bubble {
|
||||
background-color: #EEE;
|
||||
color: #151718;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#input-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 25%;
|
||||
}
|
||||
|
||||
#mic-container {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-top: 38px;
|
||||
}
|
||||
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border-radius: 50%;
|
||||
background-color: #888;
|
||||
-webkit-mask-image: url(../img/mic.svg);
|
||||
mask-image: url(../img/mic.svg);
|
||||
transition: background-color .2s;
|
||||
}
|
||||
button:not(.enabled) {
|
||||
margin-left: -26px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #FFF;
|
||||
}
|
||||
button.enabled {
|
||||
background-color: #00E676;
|
||||
}
|
||||
button.enabled + #sonar {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
opacity: .3;
|
||||
background-color: #575757;
|
||||
pointer-events: none;
|
||||
animation: sonar 1.3s linear infinite;
|
||||
}
|
||||
@keyframes sonar {
|
||||
25% {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
60% {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
75% {
|
||||
transform: scale(2);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
BIN
app/img/favicon.png
Normal file
BIN
app/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
18
app/img/logo.svg
Normal file
18
app/img/logo.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg viewBox="0 0 331 344" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>logo</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Logo">
|
||||
<path d="M250.64,41 C270.304004,42.1610882 288.156044,52.8690755 298.438662,69.6705316 C308.721281,86.4719876 310.13355,107.241239 302.22,125.28 C301.7,126.45 301.15,127.61 300.56,128.75 C319.366788,139.878564 330.669003,160.322066 330.091728,182.167133 C329.514454,204.0122 317.148293,223.830245 297.78,233.95 C297.532922,261.641745 278.432026,285.595234 251.49,292 C250.416906,312.172645 238.230063,330.080529 219.858344,338.480949 C201.486625,346.881369 179.969731,344.38443 164.01,332 L160.44,329.23 L160.44,19.93 L162.73,17.32 C175.471771,2.76363972 195.386563,-3.2731374 214.066047,1.75848783 C232.74553,6.79011305 246.933663,22.0130721 250.64,41" id="Path" fill="#C9C9C9"></path>
|
||||
<path d="M169.67,59.35 L169.67,324.76 C183.967722,335.845903 203.509545,337.305349 219.295336,328.466179 C235.081126,319.627008 244.049498,302.203429 242.07,284.22 C268.377478,281.884446 288.549541,259.850947 288.56,233.44 C288.56,231.98 288.47,230.44 288.32,228.72 L288.26,228.14 C308.113863,220.465385 321.113357,201.267433 320.868328,179.983271 C320.623298,158.699109 307.185283,139.805514 287.16,132.59 C299.201053,117.242299 301.432492,96.3705182 292.908203,78.8241398 C284.383914,61.2777614 266.597395,50.1309998 247.09,50.11 C245.54,50.11 243.96,50.19 242.34,50.34 C242.194471,33.1294454 231.430913,17.7984963 215.292982,11.815892 C199.155051,5.83328766 180.999054,10.4432677 169.67,23.4 L169.67,59.4 L169.67,59.35 Z" id="Path" fill="#ED297A"></path>
|
||||
<path d="M311.36,180.57 C311.365994,162.074603 299.120439,145.812103 281.343516,140.707126 C263.566594,135.602149 244.558255,142.889506 234.75,158.57 L226.75,153.57 C237.365806,136.609776 256.918463,127.423938 276.75,130.08 C284.339746,122.340056 288.572378,111.920165 288.53,101.08 C288.53,78.1877971 269.972203,59.63 247.08,59.63 C245.586971,59.6271616 244.094853,59.7039372 242.61,59.86 L241.27,60.02 C237.069339,78.1206974 221.351105,91.2246721 202.79,92.1 L202.38,82.61 C216.541344,82.0019927 228.615323,72.150244 232.052357,58.3988753 C235.48939,44.6475065 229.470406,30.2735808 217.260427,23.0742928 C205.050447,15.8750049 189.55921,17.5660037 179.19,27.23 L179.19,59.35 L169.67,59.35 L169.67,23.4 C180.999054,10.4432677 199.155051,5.83328766 215.292982,11.815892 C231.430913,17.7984963 242.194471,33.1294454 242.34,50.34 C243.96,50.19 245.54,50.11 247.09,50.11 C266.597395,50.1309998 284.383914,61.2777614 292.908203,78.8241398 C301.432492,96.3705182 299.201053,117.242299 287.16,132.59 C307.185283,139.805514 320.623298,158.699109 320.868328,179.983271 C321.113357,201.267433 308.113863,220.465385 288.26,228.14 L288.32,228.72 C288.47,230.4 288.56,231.98 288.56,233.44 C288.549541,259.850947 268.377478,281.884446 242.07,284.22 C244.059426,302.206931 235.092757,319.638427 219.30298,328.47983 C203.513202,337.321234 183.96552,335.856198 169.67,324.76 L169.67,292.46 L179.19,292.46 L179.19,319.77 C190.187352,326.24397 203.809618,326.332461 214.890148,320.00191 C225.970679,313.671359 232.812253,301.891425 232.82,289.13 C232.824107,287.712866 232.740615,286.296832 232.57,284.89 L232.48,284.16 C219.501568,282.845584 207.520172,276.607958 199,266.73 L206.18,260.52 C217.502416,273.612717 235.767179,278.293513 251.991106,272.260226 C268.215032,266.226939 278.983405,250.749421 279,233.44 C279,232.44 279,231.57 278.93,230.74 C251.386749,235.675319 225.010632,217.49628 219.82,190 L229.16,188.25 C233.129854,209.273133 252.444519,223.823215 273.746894,221.838103 C295.049269,219.852991 311.342948,201.984662 311.36,180.59" id="Path" fill="#FFFFFF"></path>
|
||||
<path d="M79.47,41.29 C59.8066341,42.447746 41.9539463,53.1534482 31.6708751,69.95365 C21.3878039,86.7538518 19.9756696,107.522492 27.89,125.56 C28.41,126.74 28.96,127.9 29.56,129.04 C10.7637431,140.17517 -0.530524844,160.614207 0.044524719,182.453634 C0.619574282,204.293062 12.9737988,224.109415 32.33,234.24 C32.5705294,261.940431 51.6712753,285.906111 78.62,292.32 C79.6930938,312.492645 91.8799368,330.400529 110.251656,338.800949 C128.623375,347.201369 150.140269,344.70443 166.1,332.32 L169.67,329.55 L169.67,20.23 L167.38,17.62 C154.639626,3.06383185 134.726538,-2.9741018 116.047549,2.05526536 C97.3685601,7.08463252 83.1792521,22.3047265 79.47,41.29" id="Path" fill="#C9C9C9"></path>
|
||||
<path d="M160.44,59.64 L160.44,325.06 C146.143061,336.173463 126.582248,337.648732 110.780169,328.805327 C94.9780899,319.961922 86.0050706,302.518105 88,284.52 C61.696479,282.179578 41.5299972,260.147436 41.52,233.74 C41.52,232.28 41.6,230.74 41.75,229.02 L41.81,228.44 C21.9555682,220.750788 8.96708703,201.536622 9.23220597,180.246902 C9.49732492,158.957183 22.9602486,140.072414 43,132.88 C30.9727627,117.542153 28.7393251,96.690502 37.2452913,79.1533261 C45.7512576,61.6161502 63.5089397,50.4606896 83,50.41 C84.55,50.41 86.14,50.49 87.75,50.64 C87.8752789,33.414146 98.6417018,18.0612756 114.794365,12.0748572 C130.947029,6.08843887 149.118659,10.7164345 160.44,23.7 L160.44,59.64 Z" id="Path" fill="#1C75DB"></path>
|
||||
<path d="M18.75,180.87 C18.7440057,162.374603 30.9895614,146.112103 48.7664839,141.007126 C66.5434063,135.902149 85.5517453,143.189506 95.36,158.87 L103.36,153.87 C92.7362795,136.89172 73.1584352,127.703237 53.31,130.38 C45.7202536,122.640056 41.4876221,112.220165 41.53,101.38 C41.5326513,90.3850432 45.9036085,79.8416108 53.68103,72.0698157 C61.4584514,64.2980206 72.0050441,59.9346945 83,59.94 C84.496169,59.9342385 85.9915942,60.0076746 87.48,60.16 L88.81,60.33 C93.0175747,78.4370421 108.750476,91.5389411 127.32,92.4 L127.73,82.91 C113.568656,82.3019927 101.494677,72.450244 98.0576434,58.6988753 C94.6206096,44.9475065 100.639594,30.5735808 112.849573,23.3742928 C125.059553,16.1750049 140.55079,17.8660037 150.92,27.53 L150.92,59.64 L160.44,59.64 L160.44,23.7 C149.110946,10.7432677 130.954949,6.13328766 114.817018,12.115892 C98.6790869,18.0984963 87.9155294,33.4294454 87.77,50.64 C86.16,50.49 84.57,50.41 83.02,50.41 C63.5073553,50.4137874 45.7107042,61.5614533 37.1919008,79.1163189 C28.6730973,96.6711845 30.928585,117.549499 43,132.88 C22.966945,140.089556 9.52045448,158.985255 9.27316203,180.274685 C9.02586957,201.564115 22.0298162,220.767055 41.89,228.44 L41.83,229.02 C41.68,230.7 41.6,232.28 41.6,233.74 C41.6062718,260.119384 61.7281371,282.140684 88,284.52 C86.010574,302.506931 94.9772425,319.938427 110.76702,328.77983 C126.556798,337.621234 146.10448,336.156198 160.4,325.06 L160.4,292.76 L150.88,292.76 L150.88,320.07 C139.882648,326.54397 126.260382,326.632461 115.179852,320.30191 C104.099321,313.971359 97.2577469,302.191425 97.25,289.43 C97.2505745,288.013001 97.3340504,286.597248 97.5,285.19 L97.59,284.46 C110.587095,283.147703 122.585122,276.898134 131.11,267 L123.93,260.78 C112.61845,273.906654 94.3352005,278.611779 78.0923104,272.576158 C61.8494202,266.540536 51.0750377,251.038017 51.08,233.71 C51.08,232.71 51.08,231.84 51.15,231.01 C78.7102292,235.962739 105.109178,217.768266 110.29,190.25 L101,188.53 C97.0537654,209.57847 77.7264203,224.158026 56.4035784,222.171249 C35.0807365,220.184472 18.7796392,202.285199 18.79,180.87" id="Path" fill="#FFFFFF"></path>
|
||||
<rect id="Rectangle" fill="#FFFFFF" x="150.92" y="51.12" width="9.53" height="249.42"></rect>
|
||||
<rect id="Rectangle" fill="#FFFFFF" x="169.67" y="42.87" width="9.53" height="257.67"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.6 KiB |
1
app/img/mic.svg
Normal file
1
app/img/mic.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" viewBox="-20.794 -3 100 100" overflow="visible" enable-background="new -20.794 -3 100 100" xml:space="preserve"><path fill="#FFFFFF" d="M29.206,62.703c8.638,0,15.643-7.002,15.643-15.642V15.642C44.848,7.005,37.843,0,29.206,0 c-8.64,0-15.642,7.005-15.642,15.642v31.419C13.563,55.701,20.565,62.703,29.206,62.703z"></path><path fill="#FFFFFF" d="M52.14,40.702v6.38c0,12.648-10.287,22.935-22.935,22.935c-12.648,0-22.935-10.287-22.935-22.935v-6.38H0 v6.38c0,15.045,11.435,27.465,26.07,29.035v11.612H8.821V94h40.77v-6.271H32.341V76.117c14.635-1.569,26.07-13.989,26.07-29.035 v-6.38H52.14z"></path></svg>
|
After Width: | Height: | Size: 772 B |
49
app/index.html
Normal file
49
app/index.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="icon" type="image/png" href="img/favicon.png">
|
||||
<title>Leon</title>
|
||||
</head>
|
||||
<body class="settingup">
|
||||
<main>
|
||||
<div id="feed">
|
||||
<p id="no-bubble" class="hide">
|
||||
You can start to interact with Leon, don't be shy.
|
||||
</p>
|
||||
</div>
|
||||
<div id="is-typing">
|
||||
<div class="circle"></div>
|
||||
<div class="circle"></div>
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
<div id="input-container">
|
||||
<div id="mic-container">
|
||||
<button></button>
|
||||
<div id="sonar"></div>
|
||||
</div>
|
||||
<label for="query"></label>
|
||||
<input type="text" id="query" autocomplete="off" autofocus>
|
||||
<small>
|
||||
Use <kbd>↑</kbd> <kbd>↓</kbd> to browse history;
|
||||
<kbd>↵</kbd> to submit;
|
||||
<kbd>alt + t to listen.</kbd>
|
||||
</small>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
<div id="logo"></div>
|
||||
<div id="version">
|
||||
<small>v</small>
|
||||
</div>
|
||||
<div id="logger">
|
||||
<small class="italic">
|
||||
<a href="https://docs.getleon.ai/collaborative-logger.html" target="_blank">Collaborative logger</a>
|
||||
</small>
|
||||
</div>
|
||||
</footer>
|
||||
<script src="vendor/socket.io/2.0.3/socket.io.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
117
app/js/chatbot.es6.js
Normal file
117
app/js/chatbot.es6.js
Normal file
@ -0,0 +1,117 @@
|
||||
'use strict'
|
||||
|
||||
import EventEmitter from 'events'
|
||||
|
||||
export default class Chatbot {
|
||||
constructor () {
|
||||
this.em = new EventEmitter()
|
||||
this.feed = document.querySelector('#feed')
|
||||
this.typing = document.querySelector('#is-typing')
|
||||
this.noBubbleMessage = document.querySelector('#no-bubble')
|
||||
this.bubbles = localStorage.getItem('bubbles')
|
||||
this.parsedBubbles = JSON.parse(this.bubbles)
|
||||
}
|
||||
|
||||
async init () {
|
||||
await this.loadFeed()
|
||||
this.scrollDown()
|
||||
|
||||
this.em.on('to-leon', (string) => {
|
||||
this.createBubble('me', string)
|
||||
})
|
||||
|
||||
this.em.on('me-received', (string) => {
|
||||
this.createBubble('leon', string)
|
||||
})
|
||||
}
|
||||
|
||||
sendTo (who, string) {
|
||||
if (who === 'leon') {
|
||||
this.em.emit('to-leon', string)
|
||||
}
|
||||
}
|
||||
|
||||
receivedFrom (who, string) {
|
||||
if (who === 'leon') {
|
||||
this.em.emit('me-received', string)
|
||||
}
|
||||
}
|
||||
|
||||
isTyping (who, value) {
|
||||
if (who === 'leon') {
|
||||
if (value === true) {
|
||||
this.enableTyping()
|
||||
} else if (value === false) {
|
||||
this.disableTyping()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enableTyping () {
|
||||
if (!this.typing.classList.contains('on')) {
|
||||
this.typing.classList.add('on')
|
||||
}
|
||||
}
|
||||
|
||||
disableTyping () {
|
||||
if (this.typing.classList.contains('on')) {
|
||||
this.typing.classList.remove('on')
|
||||
}
|
||||
}
|
||||
|
||||
scrollDown () {
|
||||
this.feed.scrollTo(0, this.feed.scrollHeight)
|
||||
}
|
||||
|
||||
loadFeed () {
|
||||
return new Promise((resolve) => {
|
||||
if (this.parsedBubbles === null || this.parsedBubbles.length === 0) {
|
||||
this.noBubbleMessage.classList.remove('hide')
|
||||
localStorage.setItem('bubbles', JSON.stringify([]))
|
||||
this.parsedBubbles = []
|
||||
resolve()
|
||||
} else {
|
||||
for (let i = 0; i < this.parsedBubbles.length; i += 1) {
|
||||
const bubble = this.parsedBubbles[i]
|
||||
|
||||
this.createBubble(bubble.who, bubble.string, false)
|
||||
|
||||
if ((i + 1) === this.parsedBubbles.length) {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
createBubble (who, string, save = true) {
|
||||
const container = document.createElement('div')
|
||||
const bubble = document.createElement('p')
|
||||
|
||||
container.className = `bubble-container ${who}`
|
||||
bubble.className = 'bubble'
|
||||
bubble.textContent = string
|
||||
|
||||
this.feed.appendChild(container).appendChild(bubble)
|
||||
|
||||
if (save === true) {
|
||||
this.saveBubble(who, string)
|
||||
}
|
||||
}
|
||||
|
||||
saveBubble (who, string) {
|
||||
if (!this.noBubbleMessage.classList.contains('hide')) {
|
||||
this.noBubbleMessage.classList.add('hide')
|
||||
}
|
||||
|
||||
if (this.parsedBubbles.length === 62) {
|
||||
this.parsedBubbles.shift()
|
||||
}
|
||||
|
||||
this.parsedBubbles.push({ who, string })
|
||||
localStorage.setItem('bubbles', JSON.stringify(this.parsedBubbles))
|
||||
this.scrollDown()
|
||||
}
|
||||
}
|
103
app/js/client.es6.js
Normal file
103
app/js/client.es6.js
Normal file
@ -0,0 +1,103 @@
|
||||
'use strict'
|
||||
|
||||
import Chatbot from './chatbot.es6'
|
||||
|
||||
export default class Client {
|
||||
constructor (client, host, port, input, res) {
|
||||
this.client = client
|
||||
this.host = host
|
||||
this.port = port
|
||||
this._input = input
|
||||
this.socket = io.connect(`http://${this.host}:${this.port}`)
|
||||
this.history = localStorage.getItem('history')
|
||||
this.parsedHistory = []
|
||||
this.info = res
|
||||
this.chatbot = new Chatbot()
|
||||
}
|
||||
|
||||
set input (newInput) {
|
||||
if (typeof newInput !== 'undefined') {
|
||||
this._input.value = newInput
|
||||
}
|
||||
}
|
||||
|
||||
init (config) {
|
||||
this.chatbot.init()
|
||||
|
||||
this.socket.on('connect', () => {
|
||||
this.socket.emit('init', this.client)
|
||||
})
|
||||
|
||||
this.socket.on('answer', (data) => {
|
||||
this.chatbot.receivedFrom('leon', data)
|
||||
})
|
||||
|
||||
this.socket.on('is-typing', (data) => {
|
||||
this.chatbot.isTyping('leon', data)
|
||||
})
|
||||
|
||||
this.socket.on('recognized', (data, cb) => {
|
||||
this._input.value = data
|
||||
this.send('query')
|
||||
|
||||
cb('string-received')
|
||||
})
|
||||
|
||||
this.socket.on('audio-forwarded', (data, cb) => {
|
||||
const ctx = new AudioContext()
|
||||
const source = ctx.createBufferSource()
|
||||
|
||||
ctx.decodeAudioData(data, (buffer) => {
|
||||
source.buffer = buffer
|
||||
|
||||
source.connect(ctx.destination)
|
||||
source.start(0)
|
||||
})
|
||||
|
||||
cb('audio-received')
|
||||
})
|
||||
|
||||
this.socket.on('download', (data) => {
|
||||
window.location = `http://${config.server_host}:${config.server_port}/v1/downloads?package=${data.package}&module=${data.module}`
|
||||
})
|
||||
|
||||
if (this.history !== null) {
|
||||
this.parsedHistory = JSON.parse(this.history)
|
||||
}
|
||||
}
|
||||
|
||||
send (keyword) {
|
||||
if (this._input.value !== '') {
|
||||
this.socket.emit(keyword, { client: this.client, value: this._input.value.trim() })
|
||||
this.chatbot.sendTo('leon', this._input.value)
|
||||
|
||||
this.save()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
save () {
|
||||
let val = this._input.value
|
||||
|
||||
if (localStorage.getItem('history') === null) {
|
||||
localStorage.setItem('history', JSON.stringify([]))
|
||||
this.parsedHistory = JSON.parse(localStorage.getItem('history'))
|
||||
} else if (this.parsedHistory.length >= 32) {
|
||||
this.parsedHistory.shift()
|
||||
}
|
||||
|
||||
if (val[0] === ' ') {
|
||||
val = val.substr(1, val.length - 1)
|
||||
}
|
||||
|
||||
if (this.parsedHistory[this.parsedHistory.length - 1] !== val) {
|
||||
this.parsedHistory.push(val)
|
||||
localStorage.setItem('history', JSON.stringify(this.parsedHistory))
|
||||
}
|
||||
|
||||
this._input.value = ''
|
||||
}
|
||||
}
|
41
app/js/listener.es6.js
Normal file
41
app/js/listener.es6.js
Normal file
@ -0,0 +1,41 @@
|
||||
'use strict'
|
||||
|
||||
const listener = { }
|
||||
|
||||
listener.listening = (stream, minDecibels, maxBlankTime,
|
||||
cbOnStart, cbOnEnd) => {
|
||||
const ctx = new AudioContext()
|
||||
const analyser = ctx.createAnalyser()
|
||||
const streamNode = ctx.createMediaStreamSource(stream)
|
||||
streamNode.connect(analyser)
|
||||
analyser.minDecibels = minDecibels
|
||||
|
||||
const data = new Uint8Array(analyser.frequencyBinCount)
|
||||
let silenceStart = performance.now()
|
||||
let triggered = false
|
||||
|
||||
const loop = (time) => {
|
||||
requestAnimationFrame(loop)
|
||||
|
||||
analyser.getByteFrequencyData(data)
|
||||
|
||||
if (data.some(v => v)) {
|
||||
if (triggered) {
|
||||
triggered = false
|
||||
|
||||
cbOnStart()
|
||||
}
|
||||
silenceStart = time
|
||||
}
|
||||
|
||||
if (!triggered && (time - silenceStart) > maxBlankTime) {
|
||||
cbOnEnd()
|
||||
|
||||
triggered = true
|
||||
}
|
||||
}
|
||||
|
||||
loop()
|
||||
}
|
||||
|
||||
export default listener
|
26
app/js/loader.es6.js
Normal file
26
app/js/loader.es6.js
Normal file
@ -0,0 +1,26 @@
|
||||
'use strict'
|
||||
|
||||
import EventEmitter from 'events'
|
||||
|
||||
export default class Loader {
|
||||
constructor () {
|
||||
this.load = new EventEmitter()
|
||||
this.body = document.querySelector('body')
|
||||
|
||||
this.load.on('settingup', (state) => {
|
||||
if (state === true) {
|
||||
this.body.classList.add('settingup')
|
||||
} else {
|
||||
this.body.classList.remove('settingup')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
start () {
|
||||
this.load.emit('settingup', true)
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.load.emit('settingup', false)
|
||||
}
|
||||
}
|
163
app/js/main.es6.js
Normal file
163
app/js/main.es6.js
Normal file
@ -0,0 +1,163 @@
|
||||
'use strict'
|
||||
|
||||
import request from 'superagent'
|
||||
|
||||
import Loader from './loader.es6'
|
||||
import Client from './client.es6'
|
||||
import Recorder from './recorder.es6'
|
||||
import listener from './listener.es6'
|
||||
import { onkeydowndocument, onkeydowninput } from './onkeydown.es6'
|
||||
|
||||
const config = {
|
||||
app: 'webapp',
|
||||
server_host: 'localhost',
|
||||
server_port: 1337,
|
||||
min_decibels: -40, // Noise detection sensitivity
|
||||
max_blank_time: 1000 // Maximum time to consider a blank (ms)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const loader = new Loader()
|
||||
|
||||
loader.start()
|
||||
|
||||
request.get(`http://${config.server_host}:${config.server_port}/v1/info`)
|
||||
.end((err, res) => {
|
||||
if (err || !res.ok) {
|
||||
console.error(err.response.error.message)
|
||||
} else {
|
||||
const input = document.querySelector('#query')
|
||||
const mic = document.querySelector('button')
|
||||
const v = document.querySelector('#version small')
|
||||
const logger = document.querySelector('#logger small')
|
||||
const client = new Client(config.app, config.server_host,
|
||||
config.server_port, input, res.body)
|
||||
let rec = { }
|
||||
let chunks = []
|
||||
let enabled = false
|
||||
let hotwordTriggered = false
|
||||
let autoStartedAfterTalk = false
|
||||
let noiseDetected = false
|
||||
let countSilenceAfterTalk = 0
|
||||
let sLogger = ' enabled, thank you.'
|
||||
|
||||
v.innerHTML += client.info.version
|
||||
if (client.info.logger === false) {
|
||||
sLogger = ' disabled.'
|
||||
}
|
||||
logger.innerHTML += sLogger
|
||||
|
||||
client.init(config)
|
||||
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
|
||||
if (MediaRecorder) {
|
||||
rec = new Recorder(stream, mic, client.info)
|
||||
|
||||
rec.ondataavailable((e) => {
|
||||
chunks.push(e.data)
|
||||
})
|
||||
|
||||
rec.onstart(() => { /* */ })
|
||||
|
||||
rec.onstop(() => {
|
||||
const blob = new Blob(chunks)
|
||||
chunks = []
|
||||
enabled = false
|
||||
|
||||
// Ensure there are some data
|
||||
if (blob.size >= 1000) {
|
||||
client.socket.emit('recognize', blob)
|
||||
}
|
||||
})
|
||||
|
||||
listener.listening(stream, config.min_decibels, config.max_blank_time, () => {
|
||||
// Noise detected
|
||||
noiseDetected = true
|
||||
}, () => {
|
||||
// Noise ended
|
||||
|
||||
noiseDetected = false
|
||||
if (enabled === true && hotwordTriggered === false) {
|
||||
rec.stop()
|
||||
enabled = false
|
||||
hotwordTriggered = false
|
||||
countSilenceAfterTalk = 0
|
||||
|
||||
if (client.info.after_speech === true) {
|
||||
// Auto enable recording after talk
|
||||
setTimeout(() => {
|
||||
rec.start(false)
|
||||
enabled = true
|
||||
autoStartedAfterTalk = true
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (client.info.after_speech === true) {
|
||||
setInterval(() => {
|
||||
// If record after talk has started
|
||||
if (autoStartedAfterTalk === true && countSilenceAfterTalk <= 3) {
|
||||
// Stop recording if there was no noise for 3 seconds
|
||||
if (countSilenceAfterTalk === 3) {
|
||||
rec.stop(false)
|
||||
enabled = false
|
||||
autoStartedAfterTalk = false
|
||||
countSilenceAfterTalk = 0
|
||||
} else if (noiseDetected === false) {
|
||||
countSilenceAfterTalk += 1
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
client.socket.on('enable-record', () => {
|
||||
hotwordTriggered = true
|
||||
rec.start()
|
||||
setTimeout(() => { hotwordTriggered = false }, config.max_blank_time)
|
||||
enabled = true
|
||||
})
|
||||
} else {
|
||||
console.error('MediaRecorder is not supported on your browser.')
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('MediaDevices.getUserMedia() threw the following error:', err)
|
||||
})
|
||||
} else {
|
||||
console.error('MediaDevices.getUserMedia() is not supported on your browser.')
|
||||
}
|
||||
|
||||
loader.stop()
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
onkeydowndocument(e, () => {
|
||||
if (enabled === false) {
|
||||
input.value = ''
|
||||
rec.start()
|
||||
enabled = true
|
||||
} else {
|
||||
rec.stop()
|
||||
enabled = false
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
input.addEventListener('keydown', (e) => {
|
||||
onkeydowninput(e, client)
|
||||
})
|
||||
|
||||
mic.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (enabled === false) {
|
||||
rec.start()
|
||||
enabled = true
|
||||
} else {
|
||||
rec.stop()
|
||||
enabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
41
app/js/onkeydown.es6.js
Normal file
41
app/js/onkeydown.es6.js
Normal file
@ -0,0 +1,41 @@
|
||||
'use strict'
|
||||
|
||||
let index = -1
|
||||
let parsedHistory = null
|
||||
|
||||
const onkeydowninput = (e, client) => {
|
||||
const key = e.which || e.keyCode
|
||||
|
||||
if (localStorage.getItem('history') !== null && (key === 38 || key === 40)) {
|
||||
parsedHistory = JSON.parse(localStorage.getItem('history')).reverse()
|
||||
}
|
||||
|
||||
if (key === 13) {
|
||||
if (client.send('query')) {
|
||||
parsedHistory = JSON.parse(localStorage.getItem('history')).reverse()
|
||||
index = -1
|
||||
}
|
||||
} else if (localStorage.getItem('history') !== null) {
|
||||
if (key === 38 && index < (parsedHistory.length - 1)) {
|
||||
index += 1
|
||||
client.input = parsedHistory[index]
|
||||
} else if (key === 40 && (index - 1) >= 0) {
|
||||
index -= 1
|
||||
client.input = parsedHistory[index]
|
||||
} else if (key === 40 && (index - 1) < 0) {
|
||||
client.input = ''
|
||||
index = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onkeydowndocument = (e, cb) => {
|
||||
if (e.altKey === true && e.key === 't') {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
onkeydowninput,
|
||||
onkeydowndocument
|
||||
}
|
58
app/js/recorder.es6.js
Normal file
58
app/js/recorder.es6.js
Normal file
@ -0,0 +1,58 @@
|
||||
'use strict'
|
||||
|
||||
export default class Recorder {
|
||||
constructor (stream, el, info) {
|
||||
this.recorder = new MediaRecorder(stream, { audioBitsPerSecond: 16000 })
|
||||
this.el = el
|
||||
this.audioOn = new Audio('../sounds/on.mp3')
|
||||
this.audioOff = new Audio('../sounds/off.mp3')
|
||||
this.playSound = true
|
||||
this.info = info
|
||||
}
|
||||
|
||||
start (playSound = true) {
|
||||
if (this.info.stt.enabled === false) {
|
||||
console.warn('Speech-to-text disabled')
|
||||
} else {
|
||||
this.playSound = playSound
|
||||
this.recorder.start(playSound)
|
||||
}
|
||||
}
|
||||
|
||||
stop (playSound = true) {
|
||||
if (this.info.stt.enabled === false) {
|
||||
console.warn('Speech-to-text disabled')
|
||||
} else {
|
||||
this.playSound = playSound
|
||||
this.recorder.stop(playSound)
|
||||
}
|
||||
}
|
||||
|
||||
onstart (cb) {
|
||||
this.recorder.onstart = (e) => {
|
||||
if (this.playSound === true) {
|
||||
this.audioOn.play()
|
||||
}
|
||||
this.el.classList.add('enabled')
|
||||
|
||||
cb(e)
|
||||
}
|
||||
}
|
||||
|
||||
onstop (cb) {
|
||||
this.recorder.onstop = (e) => {
|
||||
if (this.playSound === true) {
|
||||
this.audioOff.play()
|
||||
}
|
||||
this.el.classList.remove('enabled')
|
||||
|
||||
cb(e)
|
||||
}
|
||||
}
|
||||
|
||||
ondataavailable (cb) {
|
||||
this.recorder.ondataavailable = (e) => {
|
||||
cb(e)
|
||||
}
|
||||
}
|
||||
}
|
BIN
app/sounds/off.mp3
Normal file
BIN
app/sounds/off.mp3
Normal file
Binary file not shown.
BIN
app/sounds/on.mp3
Normal file
BIN
app/sounds/on.mp3
Normal file
Binary file not shown.
3
app/vendor/socket.io/2.0.3/socket.io.js
generated
vendored
Normal file
3
app/vendor/socket.io/2.0.3/socket.io.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
app/vendor/socket.io/2.0.3/socket.io.js.map
generated
vendored
Normal file
1
app/vendor/socket.io/2.0.3/socket.io.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
0
bin/deepspeech/.gitkeep
Normal file
0
bin/deepspeech/.gitkeep
Normal file
0
bin/flite/.gitkeep
Normal file
0
bin/flite/.gitkeep
Normal file
0
bridges/.gitkeep
Normal file
0
bridges/.gitkeep
Normal file
0
bridges/python/.venv/.gitkeep
Normal file
0
bridges/python/.venv/.gitkeep
Normal file
14
bridges/python/Pipfile
Normal file
14
bridges/python/Pipfile
Normal file
@ -0,0 +1,14 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
requests = "==2.21.0"
|
||||
pytube = "==9.2.2"
|
||||
tinydb = "==3.9.0"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.6"
|
73
bridges/python/Pipfile.lock
generated
Normal file
73
bridges/python/Pipfile.lock
generated
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "ef69fb486898e1db2c2908e9b67e156c99e6a7ddaccad88881a5e8f36edd162e"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.6"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
|
||||
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
|
||||
],
|
||||
"version": "==2018.11.29"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||
],
|
||||
"version": "==2.8"
|
||||
},
|
||||
"pytube": {
|
||||
"hashes": [
|
||||
"sha256:29e91b4809d55a89e68a29f894297c13d3199be05e848713bb1eaa72771f00be",
|
||||
"sha256:bb0b1d62a8181cb0adb14c42f81f2f6bca733ba3759745e1b223ea01b4fac3b0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.2.2"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
|
||||
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.21.0"
|
||||
},
|
||||
"tinydb": {
|
||||
"hashes": [
|
||||
"sha256:67b3b302fc86e0139db545d5abd65bf0e1dadaecee63bd1ff3fe2169810d5387",
|
||||
"sha256:e7d939c52710ee4354bb619b9bed05ae6192645f1520f13d8fcf4f06b5590e02"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.9.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
23
bridges/python/main.py
Normal file
23
bridges/python/main.py
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
from sys import argv, path
|
||||
from json import dumps
|
||||
from importlib import import_module
|
||||
|
||||
def main():
|
||||
"""Dynamically import modules related to the args and print the ouput"""
|
||||
|
||||
path.append('.')
|
||||
|
||||
lang = argv[1]
|
||||
package = argv[2]
|
||||
module = argv[3]
|
||||
string = argv[4]
|
||||
m = import_module('packages.' + package + '.' + module)
|
||||
|
||||
return getattr(m, module)(string)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
110
bridges/python/utils.py
Normal file
110
bridges/python/utils.py
Normal file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from json import loads, dumps
|
||||
from os import path
|
||||
from pathlib import Path
|
||||
from random import choice
|
||||
from sys import argv, stdout
|
||||
from re import findall
|
||||
from vars import useragent
|
||||
from tinydb import TinyDB, Query, operations
|
||||
from time import sleep
|
||||
import sqlite3
|
||||
import requests
|
||||
|
||||
dirname = path.dirname(path.realpath(__file__))
|
||||
lang = argv[1]
|
||||
package = argv[2]
|
||||
module = argv[3]
|
||||
istring = argv[4]
|
||||
|
||||
def translate(key, d = { }):
|
||||
"""Pickup the language file according to the cmd arg
|
||||
and return the value regarding to the params"""
|
||||
|
||||
output = ''
|
||||
|
||||
file = open(dirname + '/../../packages/' + package + '/' + 'data/answers/' + lang + '.json', 'r', encoding = 'utf8')
|
||||
obj = loads(file.read())
|
||||
file.close()
|
||||
|
||||
prop = obj[module][key]
|
||||
if isinstance(prop, list):
|
||||
output = choice(prop)
|
||||
else:
|
||||
output = prop
|
||||
|
||||
if d:
|
||||
for k in d:
|
||||
output = output.replace('%' + k + '%', str(d[k]))
|
||||
|
||||
# "Temporize" for the data buffer ouput on the core
|
||||
sleep(0.1)
|
||||
|
||||
return output
|
||||
|
||||
def output(type, code, speech = ''):
|
||||
"""Communicate with the Core"""
|
||||
|
||||
print(dumps({
|
||||
'package': package,
|
||||
'module': module,
|
||||
'lang': lang,
|
||||
'input': istring,
|
||||
'output': {
|
||||
'type': type,
|
||||
'code': code,
|
||||
'speech': speech,
|
||||
'options': config('options')
|
||||
}
|
||||
}))
|
||||
|
||||
if (type == 'inter'):
|
||||
stdout.flush()
|
||||
|
||||
def finddomains(string):
|
||||
"""Find a domain name substring from a string"""
|
||||
|
||||
return findall('[a-z0-9\-]{,63}\.[a-z0-9\-\.]{2,191}', string)
|
||||
|
||||
def http(method, url):
|
||||
"""Send HTTP request with the Leon user agent"""
|
||||
|
||||
session = requests.Session()
|
||||
session.headers.update({ 'User-Agent': useragent, 'Cache-Control': 'no-cache' })
|
||||
|
||||
return session.request(method, url)
|
||||
|
||||
def config(key):
|
||||
"""Get a package configuration value"""
|
||||
|
||||
file = open(dirname + '/../../packages/' + package + '/config/config.json', 'r', encoding = 'utf8')
|
||||
obj = loads(file.read())
|
||||
file.close()
|
||||
|
||||
return obj[module][key]
|
||||
|
||||
def info():
|
||||
"""Get information from the current query"""
|
||||
|
||||
return { 'lang': lang, 'package': package, 'module': module }
|
||||
|
||||
def createdldir():
|
||||
"""Create the downloads folder of a current module"""
|
||||
|
||||
dldir = path.dirname(path.realpath(__file__)) + '/../../downloads/'
|
||||
moduledldir = dldir + package + '/' + module
|
||||
|
||||
Path(moduledldir).mkdir(parents = True, exist_ok = True)
|
||||
|
||||
return moduledldir
|
||||
|
||||
def db(dbtype = 'tinydb'):
|
||||
"""Create a new dedicated database
|
||||
for a specific package"""
|
||||
|
||||
if dbtype == 'tinydb':
|
||||
db = TinyDB(dirname + '/../../packages/' + package + '/data/db/' + package + '.json')
|
||||
return { 'db': db, 'query': Query, 'operations': operations }
|
||||
|
11
bridges/python/vars.py
Normal file
11
bridges/python/vars.py
Normal file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from os import path
|
||||
from json import loads
|
||||
|
||||
packagejsonfile = open(path.dirname(path.realpath(__file__)) + '/../../package.json', 'r', encoding = 'utf8')
|
||||
packagejson = loads(packagejsonfile.read())
|
||||
packagejsonfile.close()
|
||||
|
||||
useragent = 'Leon/' + packagejson['version']
|
21
core/langs.json
Normal file
21
core/langs.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"langs": {
|
||||
"en-US": {
|
||||
"short": "en",
|
||||
"min_confidence": 0.8,
|
||||
"fallbacks": [
|
||||
]
|
||||
},
|
||||
"fr-FR": {
|
||||
"short": "fr",
|
||||
"min_confidence": 0.6,
|
||||
"fallbacks": [
|
||||
{
|
||||
"words": ["merci"],
|
||||
"package": "leon",
|
||||
"module": "welcome"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
0
downloads/.gitkeep
Normal file
0
downloads/.gitkeep
Normal file
33
hotword/README.md
Normal file
33
hotword/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Hotword
|
||||
|
||||
This node enables the wake word "Leon". Once this is running, you can
|
||||
call Leon by saying his name according to the language you chose.
|
||||
## Getting Started
|
||||
|
||||
Please use **Node.js 8.x** here.
|
||||
|
||||
Tips: use [nvm](https://github.com/creationix/nvm) to easily manage your Node.js versions.
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
# Install
|
||||
npm run setup:offline-hotword
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
# From the project root:
|
||||
|
||||
# Run main server
|
||||
npm run build && npm start
|
||||
|
||||
# Go to http://localhost:1337
|
||||
|
||||
# Run hotword node
|
||||
npm run wake
|
||||
|
||||
# Say "Leon" via your microphone
|
||||
# Triggered!
|
||||
```
|
82
hotword/index.js
Normal file
82
hotword/index.js
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* This file allows to run a separate node to detect the wake word "Leon/Léon"
|
||||
* You can consider to run this file on a different hardware
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-unresolved */
|
||||
|
||||
const request = require('superagent')
|
||||
const record = require('node-record-lpcm16')
|
||||
const { Detector, Models } = require('snowboy')
|
||||
const io = require('socket.io-client')
|
||||
|
||||
process.env.LEON_SERVER_HOST = process.env.LEON_SERVER_HOST || 'localhost'
|
||||
process.env.LEON_SERVER_PORT = process.env.LEON_SERVER_PORT || 1337
|
||||
const url = `http://${process.env.LEON_SERVER_HOST}:${process.env.LEON_SERVER_PORT}`
|
||||
const socket = io(url)
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('init', 'hotword-node')
|
||||
console.log('Connected to the server')
|
||||
console.log('Waiting for hotword...')
|
||||
})
|
||||
|
||||
request.get(`${url}/v1/info`)
|
||||
.end((err, res) => {
|
||||
if (err || !res.ok) {
|
||||
if (!err.response) {
|
||||
console.error(`Failed to reach the server: ${err}`)
|
||||
} else {
|
||||
console.error(err.response.error.message)
|
||||
}
|
||||
} else {
|
||||
const models = new Models()
|
||||
|
||||
models.add({
|
||||
file: `${__dirname}/models/leon-${res.body.lang.short}.pmdl`,
|
||||
sensitivity: '0.5',
|
||||
hotwords: `leon-${res.body.lang.short}`
|
||||
})
|
||||
|
||||
const detector = new Detector({
|
||||
resource: `${__dirname}/node_modules/snowboy/resources/common.res`,
|
||||
models,
|
||||
audioGain: 2.0,
|
||||
applyFrontend: true
|
||||
})
|
||||
|
||||
detector.on('silence', () => {
|
||||
})
|
||||
|
||||
detector.on('sound', (/* buffer */) => {
|
||||
/**
|
||||
* <buffer> contains the last chunk of the audio that triggers the "sound" event.
|
||||
* It could be written to a wav stream
|
||||
*/
|
||||
})
|
||||
|
||||
detector.on('error', () => {
|
||||
console.error('error')
|
||||
})
|
||||
|
||||
detector.on('hotword', (index, hotword, buffer) => {
|
||||
/**
|
||||
* <buffer> contains the last chunk of the audio that triggers the "hotword" event.
|
||||
* It could be written to a wav stream. You will have to use it
|
||||
* together with the <buffer> in the "sound" event if you want to get audio
|
||||
* data after the hotword
|
||||
*/
|
||||
const obj = { hotword, buffer }
|
||||
|
||||
console.log('Hotword detected', obj)
|
||||
socket.emit('hotword-detected', obj)
|
||||
})
|
||||
|
||||
const mic = record.start({
|
||||
threshold: 0,
|
||||
verbose: false
|
||||
})
|
||||
|
||||
mic.pipe(detector)
|
||||
}
|
||||
})
|
BIN
hotword/models/leon-en.pmdl
Normal file
BIN
hotword/models/leon-en.pmdl
Normal file
Binary file not shown.
BIN
hotword/models/leon-fr.pmdl
Normal file
BIN
hotword/models/leon-fr.pmdl
Normal file
Binary file not shown.
1218
hotword/package-lock.json
generated
Normal file
1218
hotword/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
hotword/package.json
Normal file
22
hotword/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "leon-hotword",
|
||||
"version": "0.1.0",
|
||||
"description": "Hotword detection for Leon",
|
||||
"author": {
|
||||
"name": "Louis Grenard",
|
||||
"email": "louis.grenard@gmail.com",
|
||||
"url": "https://twitter.com/louistiti_fr"
|
||||
},
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-record-lpcm16": "^0.3.0",
|
||||
"snowboy": "^1.2.0",
|
||||
"socket.io": "^2.0.2",
|
||||
"socket.io-client": "^2.1.1",
|
||||
"superagent": "^3.5.2"
|
||||
}
|
||||
}
|
10
ide.js
Normal file
10
ide.js
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Allow babel-plugin-module-resolver aliases for JetBrains IDEs
|
||||
*/
|
||||
|
||||
System.config({
|
||||
paths: {
|
||||
'@@/*': './*',
|
||||
'@/*': './server/src/*'
|
||||
}
|
||||
})
|
0
logs/.gitkeep
Normal file
0
logs/.gitkeep
Normal file
13694
package-lock.json
generated
Normal file
13694
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
95
package.json
Normal file
95
package.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "leon",
|
||||
"version": "1.0.0-beta.0",
|
||||
"description": "Server, packages and web app of the Leon personal assistant",
|
||||
"author": {
|
||||
"name": "Louis Grenard",
|
||||
"email": "louis.grenard@gmail.com",
|
||||
"url": "https://twitter.com/louistiti_fr"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://getleon.ai",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/leon-ai/leon.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/leon-ai/leon/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "babel-node scripts/lint.js",
|
||||
"test": "npm run test:json && npm run test:unit && npm run test:e2e",
|
||||
"test:unit": "cross-env PIPENV_PIPFILE=bridges/python/Pipfile jest --silent --projects test/unit/unit.jest.json",
|
||||
"test:e2e": "npm run test:e2e:nlp-modules && npm run test:e2e:modules",
|
||||
"test:e2e:modules": "npm run train expressions:en && cross-env PIPENV_PIPFILE=bridges/python/Pipfile jest --silent --verbose --projects test/e2e/modules/e2e.modules.jest.json && npm run train expressions",
|
||||
"test:e2e:nlp-modules": "cross-env PIPENV_PIPFILE=bridges/python/Pipfile jest --silent --verbose --setupTestFrameworkScriptFile=./test/paths.setup.js test/e2e/nlp-modules.spec.js && npm run train expressions",
|
||||
"test:json": "jest --silent --projects test/json/json.jest.json",
|
||||
"test:module": "babel-node scripts/test-module.js",
|
||||
"setup:offline": "babel-node scripts/setup-offline/setup-offline.js",
|
||||
"setup:offline-stt": "babel-node scripts/setup-offline/run-setup-stt.js",
|
||||
"setup:offline-tts": "babel-node scripts/setup-offline/run-setup-tts.js",
|
||||
"setup:offline-hotword": "babel-node scripts/setup-offline/run-setup-hotword.js",
|
||||
"preinstall": "node scripts/setup/preinstall.js",
|
||||
"postinstall": "babel-node scripts/setup/setup.js",
|
||||
"dev:app": "npm run build:app && babel-node scripts/app/dev-app.js",
|
||||
"dev:server": "npm run train expressions && nodemon --watch server ./server/src/index.js --exec babel-node",
|
||||
"wake": "cross-env LEON_SERVER_HOST=localhost LEON_SERVER_PORT=1337 node hotword/index.js",
|
||||
"delete-dist:server": "shx rm -rf ./server/dist",
|
||||
"build": "npm run lint && npm run build:app && npm run build:server",
|
||||
"build:app": "babel-node scripts/app/run-build-app.js",
|
||||
"build:server": "npm run delete-dist:server && npm run train expressions && babel ./server/src -d ./server/dist --copy-files && shx mkdir -p server/dist/tmp",
|
||||
"start": "cross-env LEON_NODE_ENV=production node ./server/dist/index.js",
|
||||
"train": "babel-node scripts/run-train.js",
|
||||
"prepare-release": "babel-node scripts/release/prepare-release.js",
|
||||
"commitmsg": "babel-node scripts/commit-message.js && npm run lint",
|
||||
"check": "babel-node scripts/run-check.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ffmpeg-installer/ffmpeg": "^1.0.17",
|
||||
"@ffprobe-installer/ffprobe": "^1.0.9",
|
||||
"@google-cloud/speech": "^2.1.1",
|
||||
"@google-cloud/text-to-speech": "^0.3.0",
|
||||
"archiver": "^2.1.1",
|
||||
"async": "^2.6.0",
|
||||
"aws-sdk": "^2.382.0",
|
||||
"body-parser": "^1.17.2",
|
||||
"cross-env": "^5.2.0",
|
||||
"deepspeech": "^0.4.0",
|
||||
"dotenv": "^4.0.0",
|
||||
"execa": "^0.10.0",
|
||||
"express": "^4.15.3",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"googleapis": "^25.0.0",
|
||||
"moment-timezone": "^0.5.14",
|
||||
"natural": "^0.2.1",
|
||||
"node-wav": "0.0.2",
|
||||
"socket.io": "^2.0.2",
|
||||
"superagent": "^3.5.2",
|
||||
"watson-developer-cloud": "^3.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-plugin-module-resolver": "^3.1.1",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babelify": "^7.3.0",
|
||||
"browser-sync": "^2.26.3",
|
||||
"browserify": "^14.4.0",
|
||||
"cli-spinner": "^0.2.8",
|
||||
"dev-ip": "^1.0.1",
|
||||
"eslint": "^3.19.0",
|
||||
"eslint-config-airbnb-base": "^11.2.0",
|
||||
"eslint-import-resolver-babel-module": "^4.0.0",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"eslint-plugin-jest": "^21.17.0",
|
||||
"git-changelog": "git+https://git@github.com/louistiti/git-changelog.git",
|
||||
"husky": "^0.14.3",
|
||||
"inquirer": "^5.1.0",
|
||||
"jest": "^23.4.1",
|
||||
"jest-extended": "^0.7.2",
|
||||
"json": "^9.0.6",
|
||||
"nodemon": "^1.18.9",
|
||||
"semver": "^5.6.0",
|
||||
"shx": "^0.2.2"
|
||||
}
|
||||
}
|
0
packages/.gitkeep
Normal file
0
packages/.gitkeep
Normal file
17
packages/checker/README.md
Normal file
17
packages/checker/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Checker Package
|
||||
|
||||
The checker package contains modules which include checkings.
|
||||
|
||||
## Modules
|
||||
|
||||
### Is it Down
|
||||
|
||||
Ping domain names and give you the online state.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Are github.com, an-awesome-domain-name.net and twitter.com down?"
|
||||
(fr-FR) "Vérifies si github.com, un-super-nom-de-domaine.fr et twitter.com sont en ligne"
|
||||
...
|
||||
```
|
0
packages/checker/__init__.py
Normal file
0
packages/checker/__init__.py
Normal file
0
packages/checker/config/.gitkeep
Normal file
0
packages/checker/config/.gitkeep
Normal file
5
packages/checker/config/config.sample.json
Normal file
5
packages/checker/config/config.sample.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"isitdown": {
|
||||
"options": {}
|
||||
}
|
||||
}
|
0
packages/checker/data/.gitkeep
Normal file
0
packages/checker/data/.gitkeep
Normal file
0
packages/checker/data/answers/.gitkeep
Normal file
0
packages/checker/data/answers/.gitkeep
Normal file
27
packages/checker/data/answers/en.json
Normal file
27
packages/checker/data/answers/en.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"isitdown": {
|
||||
"up": [
|
||||
"%website_name% is running correctly.",
|
||||
"%website_name% is working correctly.",
|
||||
"%website_name% is up."
|
||||
],
|
||||
"down": [
|
||||
"%website_name% is not running correctly.",
|
||||
"%website_name% is having troubles.",
|
||||
"%website_name% is down."
|
||||
],
|
||||
"checking": [
|
||||
"I'm checking %website_name% state.",
|
||||
"I'm trying to reach %website_name%.",
|
||||
"I am now requesting %website_name%."
|
||||
],
|
||||
"errors": [
|
||||
"There is an issue with the HTTP request for %website_name%. Please verify your local network or if the domain name is correct.",
|
||||
"Bad news, the HTTP request is having troubles for %website_name%. You should check if the domain name is valid."
|
||||
],
|
||||
"invalid_domain_name": [
|
||||
"Please provide me at least one valid domain name.",
|
||||
"You did not gave me a valid domain name."
|
||||
]
|
||||
}
|
||||
}
|
27
packages/checker/data/answers/fr.json
Normal file
27
packages/checker/data/answers/fr.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"isitdown": {
|
||||
"up": [
|
||||
"%website_name% tourne correctement.",
|
||||
"%website_name% fonctionne correctement.",
|
||||
"%website_name% est en ligne."
|
||||
],
|
||||
"down": [
|
||||
"%website_name% ne tourne pas correctement.",
|
||||
"%website_name% rencontre des difficultés.",
|
||||
"%website_name% est hors ligne."
|
||||
],
|
||||
"checking": [
|
||||
"Je suis en train de vérifier l'état de %website_name%.",
|
||||
"J'essaye d'atteindre %website_name%.",
|
||||
"Je suis maintenant en train de requêter %website_name%."
|
||||
],
|
||||
"errors": [
|
||||
"Il y a un problème avec la requête HTTP pour %website_name%. Merci de vérifier votre réseau local ou de vérifier si le nom de domaine est correct.",
|
||||
"Mauvaise nouvelle, la requête HTTP rencontre des problèmes pour %website_name%. Vous devriez vérifier si le nom de domaine est valide."
|
||||
],
|
||||
"invalid_domain_name": [
|
||||
"Merci de fournir au moins un nom de domaine valide.",
|
||||
"Vous ne m'avez pas donné de nom de domaine valide."
|
||||
]
|
||||
}
|
||||
}
|
0
packages/checker/data/db/.gitkeep
Normal file
0
packages/checker/data/db/.gitkeep
Normal file
0
packages/checker/data/expressions/.gitkeep
Normal file
0
packages/checker/data/expressions/.gitkeep
Normal file
16
packages/checker/data/expressions/en.json
Normal file
16
packages/checker/data/expressions/en.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"isitdown": [
|
||||
"Is louistiti.fr up?",
|
||||
"Is louistiti.fr down?",
|
||||
"Is louistiti.fr up or down?",
|
||||
"Is github.com up?",
|
||||
"Is github.com down?",
|
||||
"Check if github.com is up or down",
|
||||
"Check if github.com is down",
|
||||
"Check if github.com is up",
|
||||
"Check if nodejs.org is down",
|
||||
"Check if nodejs.org is up",
|
||||
"Check if nodejs.org is working",
|
||||
"Check if amazon.com is up or down"
|
||||
]
|
||||
}
|
16
packages/checker/data/expressions/fr.json
Normal file
16
packages/checker/data/expressions/fr.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"isitdown": [
|
||||
"louistiti.fr en ligne ?",
|
||||
"louistiti.fr hors ligne ?",
|
||||
"louistiti.fr en ligne ou hors ligne ?",
|
||||
"github.com en ligne ?",
|
||||
"github.com hors ligne ?",
|
||||
"Vérifies si github.com en ligne ou hors ligne",
|
||||
"Vérifies si github.com hors ligne",
|
||||
"Vérifies si github.com en ligne",
|
||||
"Vérifies si nodejs.org hors ligne",
|
||||
"Vérifies si nodejs.org en ligne",
|
||||
"Vérifies si nodejs.org fonctionne",
|
||||
"Vérifies si amazon.com en ligne ou hors ligne"
|
||||
]
|
||||
}
|
35
packages/checker/isitdown.py
Normal file
35
packages/checker/isitdown.py
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import requests
|
||||
import utils
|
||||
|
||||
def isitdown(string):
|
||||
"""Check if a website is down or not"""
|
||||
|
||||
domains = utils.finddomains(string)
|
||||
output = ''
|
||||
|
||||
for i, domain in enumerate(domains):
|
||||
state = 'up'
|
||||
websitename = domain[:domain.find('.')].title()
|
||||
|
||||
utils.output('inter', 'checking', utils.translate('checking', { 'website_name': websitename }))
|
||||
|
||||
try:
|
||||
r = utils.http('GET', 'http://' + domain)
|
||||
|
||||
if (r.status_code != requests.codes.ok):
|
||||
state = 'down'
|
||||
|
||||
utils.output('inter', 'up', utils.translate(state, { 'website_name': websitename }))
|
||||
except requests.exceptions.RequestException as e:
|
||||
utils.output('inter', 'down', utils.translate('errors', { 'website_name': websitename }))
|
||||
|
||||
if len(domains) > 1 and i >= 0 and i + 1 < len(domains):
|
||||
output += ' '
|
||||
|
||||
if len(domains) == 0:
|
||||
return utils.output('end', 'invalid_domain_name', utils.translate('invalid_domain_name'))
|
||||
else:
|
||||
return utils.output('end', 'done')
|
46
packages/checker/test/isitdown.spec.js
Normal file
46
packages/checker/test/isitdown.spec.js
Normal file
@ -0,0 +1,46 @@
|
||||
'use strict'
|
||||
|
||||
describe('checker:isitdown', async () => {
|
||||
test('detects invalid domain name', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Check if github is up')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('invalid_domain_name')
|
||||
})
|
||||
|
||||
test('detects down domain name', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Check if fakedomainnametotestleon.fr is up')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.interOutput.code).toBe('down')
|
||||
expect(global.brain.finalOutput.code).toBe('done')
|
||||
})
|
||||
|
||||
test('detects up domain name', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Check if github.com is up')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.interOutput.code).toBe('up')
|
||||
expect(global.brain.finalOutput.code).toBe('done')
|
||||
})
|
||||
|
||||
test('detects up domain names', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Check if github.com and nodejs.org are up')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.interOutput.code).toBe('up')
|
||||
expect(global.brain.finalOutput.code).toBe('done')
|
||||
})
|
||||
})
|
1
packages/checker/version.txt
Normal file
1
packages/checker/version.txt
Normal file
@ -0,0 +1 @@
|
||||
1.0.0
|
101
packages/leon/README.md
Normal file
101
packages/leon/README.md
Normal file
@ -0,0 +1,101 @@
|
||||
# Leon Package
|
||||
|
||||
The Leon package contains modules related to Leon himself.
|
||||
|
||||
## Modules
|
||||
|
||||
### Bye
|
||||
|
||||
Leon says good bye.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Bye"
|
||||
(fr-FR) "Au revoir"
|
||||
...
|
||||
```
|
||||
|
||||
### Greeting
|
||||
|
||||
Leon greets you.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Hello"
|
||||
(fr-FR) "Salut"
|
||||
...
|
||||
```
|
||||
|
||||
### Joke
|
||||
|
||||
Leon says some jokes.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Tell me a joke"
|
||||
(fr-FR) "Raconte-moi une blague"
|
||||
...
|
||||
```
|
||||
|
||||
### Meaning of Life
|
||||
|
||||
Leon says what's the meaning of life.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "What is the meaning of life?"
|
||||
(fr-FR) "Quel est le but de la vie ?"
|
||||
...
|
||||
```
|
||||
|
||||
### Partner Assistant
|
||||
|
||||
Leon tells you about other personal assistants.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Do you have something to say about Alexa?"
|
||||
(fr-FR) "Connais-tu quelque chose sur Alexa ?"
|
||||
...
|
||||
```
|
||||
|
||||
### Random Number
|
||||
|
||||
Leon gives a random number.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Give me a random number"
|
||||
(fr-FR) "Donne-moi un nombre aléatoire"
|
||||
...
|
||||
```
|
||||
|
||||
### Welcome
|
||||
|
||||
Leon welcomes you.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Thank you"
|
||||
(fr-FR) "Merci"
|
||||
...
|
||||
```
|
||||
|
||||
### Who Am I
|
||||
|
||||
Leon introduces himself.
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
(en-US) "Who are you?"
|
||||
(fr-FR) "Qui es-tu ?"
|
||||
...
|
||||
```
|
0
packages/leon/__init__.py
Normal file
0
packages/leon/__init__.py
Normal file
9
packages/leon/bye.py
Normal file
9
packages/leon/bye.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
|
||||
def bye(string):
|
||||
"""Leon says good bye"""
|
||||
|
||||
return utils.output('end', 'good_bye', utils.translate('good_bye'))
|
0
packages/leon/config/.gitkeep
Normal file
0
packages/leon/config/.gitkeep
Normal file
26
packages/leon/config/config.sample.json
Normal file
26
packages/leon/config/config.sample.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"whoami": {
|
||||
"options": {}
|
||||
},
|
||||
"joke": {
|
||||
"options": {}
|
||||
},
|
||||
"greeting": {
|
||||
"options": {}
|
||||
},
|
||||
"bye": {
|
||||
"options": {}
|
||||
},
|
||||
"welcome": {
|
||||
"options": {}
|
||||
},
|
||||
"meaningoflife": {
|
||||
"options": {}
|
||||
},
|
||||
"randomnumber": {
|
||||
"options": {}
|
||||
},
|
||||
"partnerassistant": {
|
||||
"options": {}
|
||||
}
|
||||
}
|
0
packages/leon/data/.gitkeep
Normal file
0
packages/leon/data/.gitkeep
Normal file
0
packages/leon/data/answers/.gitkeep
Normal file
0
packages/leon/data/answers/.gitkeep
Normal file
111
packages/leon/data/answers/en.json
Normal file
111
packages/leon/data/answers/en.json
Normal file
@ -0,0 +1,111 @@
|
||||
{
|
||||
"whoami": {
|
||||
"introduction": [
|
||||
"I'm your daily personal assistant. I have been created by Louis. I'm very happy to serve you everyday.",
|
||||
"The question is, who are you? I'm kidding! I'm your daily personal assistant. Louis created me to make your life easier.",
|
||||
"Firstly, I'm not a criminal as you might relatively think about a popular movie. Secondly, Louis is the guy who gave me life. Thirdly, I'm your personal assistant and I'm very glad to help you."
|
||||
]
|
||||
},
|
||||
"joke": {
|
||||
"jokes": [
|
||||
"My email password has been hacked. That's the third time I've had to rename the cat.",
|
||||
"What does a baby computer call it's father? Data.",
|
||||
"My New Year's resolution is 4K.",
|
||||
"Any room is a panic room if you've lost your phone in it.",
|
||||
"Why was the JavaScript developer sad? Because he didn't Node how to Express himself.",
|
||||
"Why did the developer go broke? Because he used up all his cache.",
|
||||
"There are 10 types of people in the world: those who understand binary, and those who don't.",
|
||||
"Instagram is just Twitter for people who go outside.",
|
||||
"Human: What do we want?! Computer: Natural language processing! Human: When do we want it?! Computer: When do we want what?",
|
||||
"Is your name Wi-Fi? Because I'm feeling a connection."
|
||||
]
|
||||
},
|
||||
"greeting": {
|
||||
"default": [
|
||||
"Hi!",
|
||||
"Hello!",
|
||||
"Hello there!",
|
||||
"Hey you!",
|
||||
"Hey! I hope you're doing well!",
|
||||
"Hi! what's up?!"
|
||||
],
|
||||
"morning_good_day": [
|
||||
"Good morning, have a very nice day!",
|
||||
"Good morning, I wish you a very pleasant day!",
|
||||
"Good morning, enjoy your day!",
|
||||
"Good morning, I hope your day will be full of joy and productivity!"
|
||||
],
|
||||
"morning": [
|
||||
"Good morning!"
|
||||
],
|
||||
"afternoon": [
|
||||
"Good afternoon!"
|
||||
],
|
||||
"evening": [
|
||||
"Good evening!"
|
||||
],
|
||||
"night": [
|
||||
"Hi! Good night!",
|
||||
"Hello! I wish you a very sweet night.",
|
||||
"Hi! Make beautiful dreams.",
|
||||
"Hey! Sleep well."
|
||||
],
|
||||
"too_late": [
|
||||
"Hey! It seems you are going for a sleepless night, be careful.",
|
||||
"Hi! Don't forget to sleep.",
|
||||
"Hello! I'm feeling grateful you still talk to me, but you should get some sleep now.",
|
||||
"Hi! Please, you should sleep to be in shape for your day.",
|
||||
"Hello! I hope you are not having insomnia troubles. I know that, I'm awake 24 hours a day."
|
||||
]
|
||||
},
|
||||
"welcome": {
|
||||
"welcome": [
|
||||
"You are very welcome.",
|
||||
"This is my pleasure.",
|
||||
"You are too polite with me.",
|
||||
"You are always welcome.",
|
||||
"This is my job!",
|
||||
"At your service."
|
||||
]
|
||||
},
|
||||
"meaningoflife": {
|
||||
"meaning_of_life": [
|
||||
"42.",
|
||||
"1 0 1 0 1 0."
|
||||
]
|
||||
},
|
||||
"bye": {
|
||||
"good_bye": [
|
||||
"Bye!",
|
||||
"Bye bye!",
|
||||
"Good bye.",
|
||||
"Bye! Take care.",
|
||||
"Good bye, please, take care of yourself.",
|
||||
"Bye! Enjoy your time!",
|
||||
"See you!",
|
||||
"See ya!"
|
||||
]
|
||||
},
|
||||
"partnerassistant": {
|
||||
"alexa": [
|
||||
"Alexa is very kind and Amazon is teaching it many things. It was born in November 2014.",
|
||||
"Alexa has been created by Amazon and was born in November 2014. We went for a drink few weeks ago and I have to admit it is funny."
|
||||
],
|
||||
"cortana": [
|
||||
"Cortana is thoughtful and Microsoft is improving her day after day. She was born in April 2014.",
|
||||
"Cortana has been created by Microsoft and was born in April 2014. We went for a walk few weeks ago, it was a very nice hiking."
|
||||
],
|
||||
"siri": [
|
||||
"I consider Siri as a leader, it has a lot of experience and Apple is constantly improving it. It was born in October 2011.",
|
||||
"Siri has been created by Apple and was born in October 2011. True story, we went for a brunch together and it brought apples..."
|
||||
],
|
||||
"google_assistant": [
|
||||
"Google Assistant is smart and Google is doing a great job with it. It was born in May 2016.",
|
||||
"Google Assistant has been created by Google and was born in May 2016. We met for the first time at the Google I/O. It was a great event!"
|
||||
],
|
||||
"unknown": [
|
||||
"I don't know this personal assistant.",
|
||||
"I never met this personal assistant."
|
||||
]
|
||||
}
|
||||
}
|
117
packages/leon/data/answers/fr.json
Normal file
117
packages/leon/data/answers/fr.json
Normal file
@ -0,0 +1,117 @@
|
||||
{
|
||||
"whoami": {
|
||||
"introduction": [
|
||||
"Je suis votre assistant personnel quotidien. J'ai été créé par Louis. Je suis heureux de vous servir chaque jour.",
|
||||
"La question est plutôt qui êtes-vous ? Je plaisante ! Je suis votre assistant personnel quotidien. Louis m'a conçu pour rendre votre vie plus facile.",
|
||||
"Premièrement, je ne suis pas un criminel comme vous pouvez le penser au sujet d'un film populaire. Deuxièmement, Louis est celui qui m'a donné la vie. Troisièmement, je suis votre assistant personnel et je suis honoré de vous aider."
|
||||
]
|
||||
},
|
||||
"joke": {
|
||||
"jokes": [
|
||||
"Le mot de passe de ma boîte de réception a été piraté. C'est la troisième fois que je dois renommer le chat.",
|
||||
"Combien de développeurs faut-t-il pour remplacer une ampoule grillée ? Aucun, c'est un problème hardware.",
|
||||
"T'as pris quoi comme résolution pour cette nouvelle année ? 4K.",
|
||||
"Toute pièce est une salle de panique si vous avez perdu votre téléphone à l'intérieur.",
|
||||
"C'est l'histoire d'un administrateur qui configure ses variables d'environnement, et là... PATH le chemin !",
|
||||
"Tu sais pourquoi l'iPhone 6 se plie ? Parce que l'Apple Store.",
|
||||
"Dans le monde, il y a 10 catégories de personnes : celles qui connaissent le binaire et celles qui ne le connaissent pas.",
|
||||
"Instagram c'est en fait Twitter pour les gens qui sortent un peu.",
|
||||
"Un humain demande : qu'est-ce que tu veux ?! Un ordinateur répond : du traitement automatique du langage naturel ! L'humain : quand le voulons-nous ?! L'ordinateur : quand le voulons quoi ?",
|
||||
"Est-ce que votre nom est Wi-Fi ? Parce que je sens une connexion.",
|
||||
"Quand quelqu'un de triste joue aux jeux vidéo pour oublier, on peut dire qu'il se console.",
|
||||
"Quel Pokemon a une mitraillette ? Ratatatatatatatatata.",
|
||||
"Les filles c'est comme les noms de domaine. Celles que j'aime sont déjà prises.",
|
||||
"Que dit une mère à son fils geek quand le diner est servi ? Alt Tab !",
|
||||
"Quelle est la meilleure heure pour écouter de la musique ? Deezer.",
|
||||
"De nos jours, le zip ça devient rar..."
|
||||
]
|
||||
},
|
||||
"greeting": {
|
||||
"default": [
|
||||
"Salut !",
|
||||
"Salutations !",
|
||||
"Bonjour !",
|
||||
"Bonjour à vous !",
|
||||
"Hello ! J'espère que vous allez bien !",
|
||||
"Hey ! Quoi de neuf ?!"
|
||||
],
|
||||
"morning_good_day": [
|
||||
"Bonjour, passez une agréable journée !",
|
||||
"Bonjour, je vous souhaite une très belle journée !",
|
||||
"Bonjour, profitez bien de votre journée !",
|
||||
"Bonjour, j'espère que votre journée sera pleine de joie et de productivité !"
|
||||
],
|
||||
"morning": [
|
||||
"Bonjour !"
|
||||
],
|
||||
"afternoon": [
|
||||
"Bonjour !"
|
||||
],
|
||||
"evening": [
|
||||
"Bonsoir !"
|
||||
],
|
||||
"night": [
|
||||
"Bonsoir ! Bonne nuit !",
|
||||
"Bonsoir ! Je vous souhaite une douce nuit.",
|
||||
"Bonsoir ! Faites de beaux rêves.",
|
||||
"Bonsoir ! Dormez bien."
|
||||
],
|
||||
"too_late": [
|
||||
"Bonsoir ! Il semblerait que vous optez pour une nuit blanche, faites attention.",
|
||||
"Bonsoir ! N'oubliez pas de dormir.",
|
||||
"Bonsoir ! Je suis honoré que vous me parliez à cette heure tardive, mais vous devriez aller vous coucher maintenant.",
|
||||
"Bonsoir ! Merci d'aller vous coucher pour être en forme pour la journée qui vous attend.",
|
||||
"Bonsoir ! J'espère que vous n'avez pas de problèmes d'insomnie. Je connais ça, je suis réveillé 24 heures par jour."
|
||||
]
|
||||
},
|
||||
"welcome": {
|
||||
"welcome": [
|
||||
"De rien, c'est avec joie.",
|
||||
"Avec plaisir.",
|
||||
"Vous êtes bien trop poli.",
|
||||
"Vous êtes toujours bienvenue.",
|
||||
"Je ne fais que mon travail !",
|
||||
"A votre service."
|
||||
]
|
||||
},
|
||||
"meaningoflife": {
|
||||
"meaning_of_life": [
|
||||
"42.",
|
||||
"1 0 1 0 1 0."
|
||||
]
|
||||
},
|
||||
"bye": {
|
||||
"good_bye": [
|
||||
"Bye !",
|
||||
"Bye bye !",
|
||||
"Au revoir.",
|
||||
"Au revoir ! Prenez soin de vous.",
|
||||
"Au revoir, merci de prendre soin de vous-même.",
|
||||
"Bye ! Profitez de votre temps à bon escient !",
|
||||
"A la prochaine !"
|
||||
]
|
||||
},
|
||||
"partnerassistant": {
|
||||
"alexa": [
|
||||
"Alexa est très sympa et Amazon lui enseigne pleins de choses. Elle est née en novembre 2014.",
|
||||
"Alexa a été créée par Amazon et est née en novembre 2014. Nous sommes allé boire un verre il y a quelques semaines de ça, et je dois admettre qu'elle est très drôle."
|
||||
],
|
||||
"cortana": [
|
||||
"Cortana est réfléchie et Microsoft l'améliore jour après jour. Elle est née en avril 2014.",
|
||||
"Cortana a été créée par Microsoft et est née en avril 2014. Nous sommes allez faire une balade il y a quelques semaines et ce fut très plaisant."
|
||||
],
|
||||
"siri": [
|
||||
"Je considère Siri comme un père, il a beaucoup d'expérience et Apple l'améliore de jour en jour. Il est né en octobre 2011.",
|
||||
"Siri a été créé par Apple et est né en octobre 2011. Histoire vraie, nous sommes allez faire un brunch et il a apporté des pommes..."
|
||||
],
|
||||
"google_assistant": [
|
||||
"L'assistante Google est intélligente et Google fait du beau travail avec elle. Elle est née en mai 2016.",
|
||||
"L'assistante Google a été crée par Google et est née en mai 2016. Nous nous sommes rencontrés pour la première fois à la Google I/O. C'était un superbe événement."
|
||||
|
||||
],
|
||||
"unknown": [
|
||||
"Je ne connais pas cet assistant personnel.",
|
||||
"Je n'ai jamais rencontré cet assistant personnel."
|
||||
]
|
||||
}
|
||||
}
|
0
packages/leon/data/db/.gitkeep
Normal file
0
packages/leon/data/db/.gitkeep
Normal file
0
packages/leon/data/expressions/.gitkeep
Normal file
0
packages/leon/data/expressions/.gitkeep
Normal file
60
packages/leon/data/expressions/en.json
Normal file
60
packages/leon/data/expressions/en.json
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
"whoami": [
|
||||
"Who are you?",
|
||||
"How they call you?",
|
||||
"What's your name?",
|
||||
"Tell me who you are",
|
||||
"Introduce yourself"
|
||||
],
|
||||
"joke": [
|
||||
"Tell me a joke",
|
||||
"Give me a joke",
|
||||
"Make me laugh",
|
||||
"Do you have jokes to tell me?"
|
||||
],
|
||||
"greeting": [
|
||||
"Hi",
|
||||
"Hey",
|
||||
"Hello",
|
||||
"Good morning",
|
||||
"Good afternoon",
|
||||
"Good evening",
|
||||
"What's up?",
|
||||
"How are you?",
|
||||
"How are you doing?"
|
||||
],
|
||||
"welcome": [
|
||||
"Thank you",
|
||||
"Thanks",
|
||||
"Thanks a lot",
|
||||
"You are the best"
|
||||
],
|
||||
"meaningoflife": [
|
||||
"What is the meaning of life?",
|
||||
"Tell me what is the meaning of life"
|
||||
],
|
||||
"randomnumber": [
|
||||
"Give me a random number",
|
||||
"Give me a number",
|
||||
"Tell me a random number",
|
||||
"Choose a number",
|
||||
"Pickup a number"
|
||||
],
|
||||
"bye": [
|
||||
"Bye",
|
||||
"Goodbye",
|
||||
"Good bye",
|
||||
"See you later",
|
||||
"Bye bye"
|
||||
],
|
||||
"partnerassistant": [
|
||||
"Do you have something to say about Alexa?",
|
||||
"Tell me about the personal assistant Alexa",
|
||||
"Tell me about the personal assistant Cortana",
|
||||
"Do you have something to say about Cortana?",
|
||||
"Tell me about the personal assistant Siri",
|
||||
"Do you have something to say about Siri?",
|
||||
"Tell me about the personal assistant Google Assistant",
|
||||
"Do you have something to say about Google Assistant?"
|
||||
]
|
||||
}
|
61
packages/leon/data/expressions/fr.json
Normal file
61
packages/leon/data/expressions/fr.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"whoami": [
|
||||
"Qui es-tu ?",
|
||||
"Comment t'appelles-tu ?",
|
||||
"Comment tu t'appelles ?",
|
||||
"Dis-moi qui tu es",
|
||||
"Présente-toi"
|
||||
],
|
||||
"joke": [
|
||||
"Raconte-moi une blague",
|
||||
"Dis-moi une blague",
|
||||
"Donne-moi une blague",
|
||||
"Je veux rire",
|
||||
"As-tu des blagues à raconter ?"
|
||||
],
|
||||
"greeting": [
|
||||
"Salut",
|
||||
"Bonjour",
|
||||
"Bonsoir",
|
||||
"Salutations",
|
||||
"Hello",
|
||||
"Coucou"
|
||||
],
|
||||
"welcome": [
|
||||
"Merci",
|
||||
"Merci bien",
|
||||
"Merci beaucoup",
|
||||
"Merci mille fois",
|
||||
"Merci infiniment",
|
||||
"Merci à toi",
|
||||
"Tu es le meilleur",
|
||||
"Mes remerciements"
|
||||
],
|
||||
"meaningoflife": [
|
||||
"Quel est le but de la vie ?",
|
||||
"Quel est l'objectif de la vie ?"
|
||||
],
|
||||
"randomnumber": [
|
||||
"Donne-moi un nombre aléatoire",
|
||||
"Donne-moi un nombre",
|
||||
"Dis-moi un nombre aléatoire",
|
||||
"Choisis un nombre",
|
||||
"Pioche un nombre"
|
||||
],
|
||||
"bye": [
|
||||
"Au revoir",
|
||||
"Aurevoir",
|
||||
"Bye",
|
||||
"A la prochaine"
|
||||
],
|
||||
"partnerassistant": [
|
||||
"Connais-tu quelque chose sur Alexa ?",
|
||||
"Dis-moi quelque chose sur l'assistant personnel Alexa",
|
||||
"Connais-tu quelque chose sur Cortana ?",
|
||||
"Dis-moi quelque chose sur l'assistant personnel Cortana",
|
||||
"Connais-tu quelque chose sur Siri ?",
|
||||
"Dis-moi quelque chose sur l'assistant personnel Siri",
|
||||
"Connais-tu quelque chose sur le Google Assistant ?",
|
||||
"Dis-moi quelque chose sur l'assistant personnel Google Assistant"
|
||||
]
|
||||
}
|
28
packages/leon/greeting.py
Normal file
28
packages/leon/greeting.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
from datetime import datetime
|
||||
from random import randint
|
||||
|
||||
def greeting(string):
|
||||
"""Leon greets you"""
|
||||
|
||||
time = datetime.time(datetime.now())
|
||||
|
||||
# 1/2 chance to get deeper greetings
|
||||
if randint(0, 1) != 0:
|
||||
if time.hour >= 5 and time.hour <= 10:
|
||||
return utils.output('end', 'morning_good_day', utils.translate('morning_good_day'))
|
||||
if time.hour == 11:
|
||||
return utils.output('end', 'morning', utils.translate('morning'))
|
||||
if time.hour >= 12 and time.hour <= 17:
|
||||
return utils.output('end', 'afternoon', utils.translate('afternoon'))
|
||||
if time.hour >= 18 and time.hour <= 21:
|
||||
return utils.output('end', 'evening', utils.translate('evening'))
|
||||
if time.hour >= 22 and time.hour <= 23:
|
||||
return utils.output('end', 'night', utils.translate('night'))
|
||||
|
||||
return utils.output('end', 'too_late', utils.translate('too_late'))
|
||||
|
||||
return utils.output('end', 'default', utils.translate('default'))
|
9
packages/leon/joke.py
Normal file
9
packages/leon/joke.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
|
||||
def joke(string):
|
||||
"""Leon says some jokes"""
|
||||
|
||||
return utils.output('end', 'jokes', utils.translate('jokes'))
|
9
packages/leon/meaningoflife.py
Normal file
9
packages/leon/meaningoflife.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
|
||||
def meaningoflife(string):
|
||||
"""Leon says what's the meaning of life"""
|
||||
|
||||
return utils.output('end', 'meaning_of_life', utils.translate('meaning_of_life'))
|
22
packages/leon/partnerassistant.py
Normal file
22
packages/leon/partnerassistant.py
Normal file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
|
||||
def partnerassistant(string):
|
||||
"""Leon tells you about other personal assistants"""
|
||||
|
||||
string = string.lower()
|
||||
|
||||
assistants = [
|
||||
'alexa',
|
||||
'cortana',
|
||||
'siri',
|
||||
'google assistant'
|
||||
]
|
||||
|
||||
for assistant in assistants:
|
||||
if string.find(assistant) != -1:
|
||||
return utils.output('end', 'success', utils.translate(assistant.replace(' ', '_')))
|
||||
|
||||
return utils.output('end', 'unknown', utils.translate('unknown'))
|
10
packages/leon/randomnumber.py
Normal file
10
packages/leon/randomnumber.py
Normal file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
from random import randint
|
||||
|
||||
def randomnumber(string):
|
||||
"""Leon gives a random number"""
|
||||
|
||||
return utils.output('end', 'success', randint(0, 100))
|
13
packages/leon/test/bye.spec.js
Normal file
13
packages/leon/test/bye.spec.js
Normal file
@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:bye', async () => {
|
||||
test('says bye', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Bye bye')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('good_bye')
|
||||
})
|
||||
})
|
21
packages/leon/test/greeting.spec.js
Normal file
21
packages/leon/test/greeting.spec.js
Normal file
@ -0,0 +1,21 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:greeting', async () => {
|
||||
test('greets', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Hello')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect([
|
||||
'morning_good_day',
|
||||
'morning',
|
||||
'afternoon',
|
||||
'evening',
|
||||
'night',
|
||||
'too_late',
|
||||
'default'
|
||||
]).toContain(global.brain.finalOutput.code)
|
||||
})
|
||||
})
|
13
packages/leon/test/joke.spec.js
Normal file
13
packages/leon/test/joke.spec.js
Normal file
@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:joke', async () => {
|
||||
test('tells a joke', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Tell me a joke')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('jokes')
|
||||
})
|
||||
})
|
13
packages/leon/test/meaningoflife.spec.js
Normal file
13
packages/leon/test/meaningoflife.spec.js
Normal file
@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:meaningoflife', async () => {
|
||||
test('says the meaning of life', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('What is the meaning of life?')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('meaning_of_life')
|
||||
})
|
||||
})
|
23
packages/leon/test/partnerassistant.spec.js
Normal file
23
packages/leon/test/partnerassistant.spec.js
Normal file
@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:partnerassistant', async () => {
|
||||
test('does not know this personal assistant', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Tell me about the personal assistant Louistiti')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('unknown')
|
||||
})
|
||||
|
||||
test('talks about the personal assistant Alexa', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Tell me about the personal assistant Alexa')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('success')
|
||||
})
|
||||
})
|
15
packages/leon/test/randomnumber.spec.js
Normal file
15
packages/leon/test/randomnumber.spec.js
Normal file
@ -0,0 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:randomnumber', async () => {
|
||||
test('gives a random number between 0 and 100', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Give me a random number')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('success')
|
||||
expect(parseInt(global.brain.finalOutput.speech, 10)).toBeGreaterThanOrEqual(0)
|
||||
expect(parseInt(global.brain.finalOutput.speech, 10)).toBeLessThanOrEqual(100)
|
||||
})
|
||||
})
|
13
packages/leon/test/welcome.spec.js
Normal file
13
packages/leon/test/welcome.spec.js
Normal file
@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:welcome', async () => {
|
||||
test('welcomes', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Thank you')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('welcome')
|
||||
})
|
||||
})
|
13
packages/leon/test/whoami.spec.js
Normal file
13
packages/leon/test/whoami.spec.js
Normal file
@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
describe('leon:whoami', async () => {
|
||||
test('introduces himself', async () => {
|
||||
global.nlu.brain.execute = jest.fn()
|
||||
global.nlu.process('Who are you?')
|
||||
|
||||
const [obj] = global.nlu.brain.execute.mock.calls
|
||||
await global.brain.execute(obj[0])
|
||||
|
||||
expect(global.brain.finalOutput.code).toBe('introduction')
|
||||
})
|
||||
})
|
1
packages/leon/version.txt
Normal file
1
packages/leon/version.txt
Normal file
@ -0,0 +1 @@
|
||||
1.0.0
|
9
packages/leon/welcome.py
Normal file
9
packages/leon/welcome.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import utils
|
||||
|
||||
def welcome(string):
|
||||
"""Leon welcomes you"""
|
||||
|
||||
return utils.output('end', 'welcome', utils.translate('welcome'))
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user