diff --git a/.gitignore b/.gitignore
index f71ec5062..021bdc8d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,4 +26,5 @@ packages/**/data/db/*.json
server/src/data/expressions/classifier.json
app/js/main.js
package.json.backup
-.python-version
\ No newline at end of file
+.python-version
+Makefile
diff --git a/package-lock.json b/package-lock.json
index 64511eda0..d89a5839b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1424,7 +1424,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-glob": {
"version": "2.0.1",
@@ -3805,13 +3806,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"dev": true,
+ "optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -6178,7 +6181,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -6593,7 +6597,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6649,6 +6654,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6692,12 +6698,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
diff --git a/packages/leonweather/LICENSE b/packages/leonweather/LICENSE
new file mode 100644
index 000000000..adf6beb67
--- /dev/null
+++ b/packages/leonweather/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 gnouf1
+
+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.
\ No newline at end of file
diff --git a/packages/leonweather/README.md b/packages/leonweather/README.md
new file mode 100644
index 000000000..792623b3f
--- /dev/null
+++ b/packages/leonweather/README.md
@@ -0,0 +1,56 @@
+![Logo](https://zupimages.net/up/19/23/fn36.png)
+# Leon Weather
+
+The Leon Weather Package contains modules related with the weather.
+
+## Features already available
+
+- Ask for the weather and temperatures in any cities in the world
+
+ ```
+ User : Can you tell me the weather in Paris ?
+ Leon : The weather in paris is clear andthe temperature is 28°C.
+ ```
+
+- Ask for the weather and temperatures for 5 days in future with correct conjugation:
+
+ ```
+ User : Can you tell me the weather in Paris tomorrow?
+ Leon : The weather in Paris on 2019-06-06 at 12:00:00 will be rain and the temperature will be 18.4 °C.
+ ```
+
+ Default hour is 12:00:00.
+
+- Ask the weather every 3 hours:
+
+ ```
+ User :What's the weather in Paris in 3 hours ?
+ Leon : The weather in Paris on 2019-06-06 at 04:15:08 will be clear and the temperature will be 9.7°C.
+ ```
+
+ ```
+ User : What's the weather in paris tomorrow at 09:00 AM?
+ Leon : The weather in Paris on 2019-06-07 at 09:00:00 will be rain and the temperature will be 15.7°C.
+ ```
+
+- Ask temperatures in Celsuis, Fahrenheit and Kelvin by changing config file:
+
+ ```json
+ {
+ "weather": {
+ "API_key": "0000",
+ "Measure":"C", <--- HERE 'C'|'F'|'K'
+ "options": {}
+ }
+ }
+ ```
+
+ As you can see on this file you can also change the API_Key, if you want to use default API_Key put `0000` in this field
+
+## Future features
+
+- Average temperature for each day
+- Some frills such as wind speed etc...
+
+## Credit
+Open Weather API : [Go](https://openweathermap.org/api)
diff --git a/packages/leonweather/__init__.py b/packages/leonweather/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/leonweather/config/config.sample.json b/packages/leonweather/config/config.sample.json
new file mode 100644
index 000000000..089d07849
--- /dev/null
+++ b/packages/leonweather/config/config.sample.json
@@ -0,0 +1,7 @@
+{
+ "weather": {
+ "API_key": "0000",
+ "Measure":"C",
+ "options": {}
+ }
+}
diff --git a/packages/leonweather/data/answers/en.json b/packages/leonweather/data/answers/en.json
new file mode 100644
index 000000000..669d4e492
--- /dev/null
+++ b/packages/leonweather/data/answers/en.json
@@ -0,0 +1,22 @@
+{
+ "weather" :{
+ "weather_t": [
+ "The weather in %cit% on %date% at %hour% is %sky% and the temperature is %t%."
+ ],
+ "weather_f": [
+ "The weather in %cit% on %date% at %hour% will be %sky% and the temperature will be %t%."
+ ],
+ "error":[
+ "Something get wrong in leonweather package."
+ ],
+ "404_city_not_found":[
+ "I can't found this city ! Maybe if you add the country code after the name, like this \"london,uk\" it's will work better !"
+ ],
+ "ezy":[
+ "Easy, easy, too many people ask weather in this minute, wait 60 seconds please."
+ ],
+ "test" :[
+ "City : %cit% %date_ref%."
+ ]
+ }
+}
diff --git a/packages/leonweather/data/answers/fr.json b/packages/leonweather/data/answers/fr.json
new file mode 100644
index 000000000..0613c2dc3
--- /dev/null
+++ b/packages/leonweather/data/answers/fr.json
@@ -0,0 +1,22 @@
+{
+ "weather" :{
+ "weather_t": [
+ "La météo de %cit% le %date% à %hour% est %sky% et la température est de %t%.",
+ ],
+ "weather_f": [
+ "La météo de %cit% le %date% à %hour% sera %sky% et la température sera de %t%.",
+ ],
+ "error":[
+ "Quelque chose a posé soucis dans le paquet."
+ ],
+ "404_city_not_found":[
+ "je ne trouve pas la ville ! Essayez d'ajouter le code du pays derrière de cette façon : \"london,uk\" ça marchera peut être mieux !"
+ ],
+ "ezy":[
+ "Doucement, je reçois trop de demande de trop de gens. Je suis limité à 60 par minutes."
+ ],
+ "town" :[
+ "City : %cit%."
+ ]
+ }
+}
diff --git a/packages/leonweather/data/expressions/en.json b/packages/leonweather/data/expressions/en.json
new file mode 100644
index 000000000..e7e81ad47
--- /dev/null
+++ b/packages/leonweather/data/expressions/en.json
@@ -0,0 +1,23 @@
+{
+ "weather": {
+ "weather" :{
+ "expressions":[
+ "What's the weather in Paris ?",
+ "Can you tell me the weather in Paris ?",
+ "What's the weather for tomorrow in Paris ?"
+ ],
+ "entities": [
+ {
+ "type": "trim",
+ "name": "city",
+ "conditions": [
+ {
+ "type": "after_first",
+ "from": "in"
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/packages/leonweather/data/expressions/fr.json b/packages/leonweather/data/expressions/fr.json
new file mode 100644
index 000000000..43960097f
--- /dev/null
+++ b/packages/leonweather/data/expressions/fr.json
@@ -0,0 +1,29 @@
+{
+ "weather": {
+ "weather" :{
+ "expressions":[
+ "Quelle est la météo à Paris ?",
+ "Quel temps fait-il à Paris ?",
+ "Peut-tu me donne la météo de Paris ?"
+ ],
+ "entities": [
+ {
+ "type": "trim",
+ "name": "city",
+ "conditions": [
+ {
+ "type": "between",
+ "from": "à",
+ "to": "?"
+ },
+ {
+ "type": "between",
+ "from": "de",
+ "to": "?"
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/packages/leonweather/test/weather.spec.js b/packages/leonweather/test/weather.spec.js
new file mode 100644
index 000000000..326c02a2a
--- /dev/null
+++ b/packages/leonweather/test/weather.spec.js
@@ -0,0 +1,43 @@
+'use strict'
+
+describe('leonweather:weather', async () => {
+ test('Check the weather today', async () => {
+ global.nlu.brain.execute = jest.fn()
+ await global.nlu.process('What\'s the weather in Paris ?')
+
+ const [obj] = global.nlu.brain.execute.mock.calls
+ await global.brain.execute(obj[0])
+
+ expect(global.brain.finalOutput.codes).toIncludeSameMembers(['weather_t'])
+ })
+
+ test('Check the weather in future', async () => {
+ global.nlu.brain.execute = jest.fn()
+ await global.nlu.process('What\'s the weather in Paris tomorrow ?')
+
+ const [obj] = global.nlu.brain.execute.mock.calls
+ await global.brain.execute(obj[0])
+
+ expect(global.brain.finalOutput.codes).toIncludeSameMembers(['weather_f'])
+ })
+
+ test('Error', async () => {
+ global.nlu.brain.execute = jest.fn()
+ await global.nlu.process('What\'s the weather in Vide0 ?')
+
+ const [obj] = global.nlu.brain.execute.mock.calls
+ await global.brain.execute(obj[0])
+
+ expect(global.brain.finalOutput.codes).toIncludeSameMembers(['error'])
+ })
+
+ test('The city does not exist', async () => {
+ global.nlu.brain.execute = jest.fn()
+ await global.nlu.process('What\'s the weather in Blublu ?')
+
+ const [obj] = global.nlu.brain.execute.mock.calls
+ await global.brain.execute(obj[0])
+
+ expect(global.brain.finalOutput.codes).toIncludeSameMembers(['404_city_not_found'])
+ })
+})
diff --git a/packages/leonweather/version.txt b/packages/leonweather/version.txt
new file mode 100644
index 000000000..7dea76edb
--- /dev/null
+++ b/packages/leonweather/version.txt
@@ -0,0 +1 @@
+1.0.1
diff --git a/packages/leonweather/weather.py b/packages/leonweather/weather.py
new file mode 100644
index 000000000..6116f235b
--- /dev/null
+++ b/packages/leonweather/weather.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+
+import utils
+import requests
+import time
+
+
+def weather(string, entities):
+ """Check the weather"""
+
+ # We init city
+ city = 'vide0'
+ # We init the time flag.
+ date_flag = 0
+ timex_ref = 'EMPTY_REF'
+ date_ref = 'EMPTY_REF'
+ date_mem = 'EMPTY_REF'
+
+ number_of_cities = 0
+ # We init API Key & check it
+ API_key = utils.config('API_key')
+ if API_key == '0000':
+ API_key = '9ad6e7083f9e9c5d558ee4d7925e17ed'
+ # We init and check the measure ID (C or F or K)
+ measure = utils.config('Measure')
+
+ # We init "lang"
+ language = utils.info()
+ language = language['lang']
+ # We search in 'entities' the name of the city
+ for item in entities:
+ if item['entity'] == 'city' and number_of_cities == 0:
+ city = item['sourceText'].lower()
+ number_of_cities = 1
+ if item['entity'] == 'date':
+ date_flag = 1
+ date_ref = item['resolution']['date']
+ timex_ref = item['resolution']['timex']
+ date_ref = date_ref.replace('00:00:00.000', '12:00:00.000')
+ if item['entity'] == 'datetime':
+ if item['resolution']['values'][0]['timex'] != 'PRESENT_REF':
+ date_flag = 1
+ date_ref = item['resolution']['values'][0]['value']
+ date_mem = date_ref
+ hour = int(date_ref[11:13])
+ if hour % 3 != 0:
+ if hour % 3 == 1:
+ hour = hour - 1
+ if hour <= 0:
+ hour = 3
+ elif hour % 3 == 2:
+ hour = hour + 1
+ if hour >= 24:
+ hour = 21
+ if hour < 10:
+ date_ref = date_ref[:11] + '0'+str(hour)+':00:00'
+ else:
+ date_ref = date_ref[:11] + str(hour)+':00:00'
+
+ # If he don't found any city
+ if city == 'vide0':
+ return utils.output('end', 'error', utils.translate('error'))
+
+ date_ref = date_ref.replace('T', ' ')
+ date_ref = date_ref[:19]
+
+ if date_flag == 0 or timex_ref == 'PRESENT_REF':
+ url = "http://api.openweathermap.org/data/2.5/weather?appid="+API_key+"&q=" + city + "&lang=" + language
+ content = requests.get(url)
+ data = content.json()
+
+ # Codes error test
+ # If it's not '200' we have trouble
+ if data['cod'] != 200:
+ # If he don't found the city he retry without symbol after the city's name
+ if data['cod'] == "404":
+ vir = city.find(',')
+ es = city.find(' ')
+ pt = city.find('.')
+
+ if vir != -1:
+ city = city[:vir]
+ elif es != -1:
+ city = city[:es]
+ elif pt != -1:
+ city = city[:pt]
+
+ url = "http://api.openweathermap.org/data/2.5/weather?appid="+API_key+"&q=" + city + "&lang=" + language
+ content = requests.get(url)
+ data = content.json()
+ if data['cod'] == "404":
+ return utils.output('end', '404_city_not_found', utils.translate('404_city_not_found'))
+ # If the number of request is higher than 60/min
+ elif data['cod'] == "429":
+ return utils.output('end', 'ezy', utils.translate('ezy'))
+ else:
+ return utils.output('end', 'error', utils.translate('error'))
+
+ t = data['main']['temp']
+ sky = data['weather'][0]['description']
+
+ date = time.strftime("%d-%m-%Y", time.localtime())
+ hour = time.strftime("%H:%M:%S", time.localtime())
+
+ elif date_flag != 0:
+ url = "http://api.openweathermap.org/data/2.5/forecast?appid="+API_key+"&q=" + city + "&lang=" + language
+ content = requests.get(url)
+ data = content.json()
+
+ # Codes error test (same)
+ if data['cod'] != "200":
+ if data['cod'] == "404":
+ vir = city.find(',')
+ es = city.find(' ')
+ pt = city.find('.')
+
+ if vir != -1:
+ city = city[:vir]
+ elif es != -1:
+ city = city[:es]
+ elif pt != -1:
+ city = city[:pt]
+ url = "http://api.openweathermap.org/data/2.5/forecast?appid="+API_key+"&q=" + city + "&lang=" + language
+ content = requests.get(url)
+ data = content.json()
+ if data['cod'] == "404":
+ return utils.output('end', '404_city_not_found', utils.translate('404_city_not_found'))
+ elif data['cod'] == "429":
+ return utils.output('end', 'ezy', utils.translate('ezy'))
+ else:
+ return utils.output('end', 'error', utils.translate('error'))
+
+ flag_w = 0
+ i = 0
+ while i < 40 and flag_w == 0:
+ if data['list'][i]['dt_txt'] == date_ref:
+ flag_w = 1
+ t = data['list'][i]['main']['temp']
+ sky = data['list'][i]['weather'][0]['main']
+ datetmp = data['list'][i]['dt_txt']
+ if date_mem != 'EMPTY_REF':
+ datetmp = date_mem
+ date = datetmp[:10]
+ hour = datetmp[10:]
+ i = i + 1
+ if flag_w == 0:
+ return utils.output('end', 'error', utils.translate('error'))
+
+ if measure == 'C':
+ # Convert in Celsuis
+ t = t-273.15
+ elif measure == 'F':
+ # Convert in Fahrenheit
+ t = t*9/5 - 459.67
+ t = round(t, 1)
+
+ vir = city.find(',')
+ es = city.find(' ')
+
+ if vir != -1:
+ city = city[:vir]
+ elif es != -1:
+ city = city[:es]
+
+ city = city.capitalize()
+ sky = sky.lower()
+ t = str(t)+'°'+measure
+
+ if date_flag != 0:
+ time_indic = '_f'
+ else:
+ time_indic = '_t'
+
+ return utils.output('end', 'weather'+time_indic, utils.translate('weather'+time_indic, {'cit': city, 'sky': sky, 't': t, 'date': date, 'hour': hour}))