mirror of
				https://github.com/KevinMidboe/termForecast.git
				synced 2025-10-29 18:00:17 +00:00 
			
		
		
		
	Moved all runnning scripts to single folder
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								termWeather/conf/GeoLite2-City.mmdb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								termWeather/conf/GeoLite2-City.mmdb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 51 MiB | 
							
								
								
									
										154
									
								
								termWeather/emojiParser.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										154
									
								
								termWeather/emojiParser.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,154 @@ | |||||||
|  | #!/usr/bin/env python3.6 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # @Author: KevinMidboe | ||||||
|  | # @Date:   2017-07-29 11:56:24 | ||||||
|  | # @Last Modified by:   KevinMidboe | ||||||
|  | # @Last Modified time: 2017-07-30 13:17:19 | ||||||
|  |  | ||||||
|  | from fuzzywuzzy import process | ||||||
|  |  | ||||||
|  | # Find the first word, if it is a noun or a adjective. ✔️ | ||||||
|  | # Remove the adjective and split if there is a AND ✔️ | ||||||
|  | # Then match the first noun to list and add that emoji ✔️ | ||||||
|  | # and then match the second to list and add that emoji ✔️ | ||||||
|  | # REGEX this bitch up  | ||||||
|  |  | ||||||
|  | symbol_table = { | ||||||
|  | 	'clear sky': '☀️', | ||||||
|  | 	'fair': '🌤', | ||||||
|  | 	'partly cloudy': '⛅️', | ||||||
|  | 	'cloudy': ' ☁️ ', | ||||||
|  | 	'thunder': '⚡️', | ||||||
|  | 	 | ||||||
|  | 	'rain showers': '🌦', | ||||||
|  | 	'rain': '🌧', | ||||||
|  | 	'sleet showers': '🌦 💦', | ||||||
|  | 	'sleet': '🌨 💦', | ||||||
|  | 	'snow showers': '⛅ ❄️', | ||||||
|  | 	'snow': '🌨', | ||||||
|  |  | ||||||
|  | 	'rain': '🌧', | ||||||
|  | 	'sleet': '🌧', | ||||||
|  | 	'snow': '🌨', | ||||||
|  |  | ||||||
|  | 	'showers': '🌤' | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | severity = { | ||||||
|  | 		'rain': ['', ' ☂️', ' ☔️'], | ||||||
|  | 		'sleet': [' 💦 ', ' 💧 ', ' 💧 💦 '], | ||||||
|  | 		'snow': [' ❄️ ', ' ❄️ ❄️ ', ' ❄️ ❄️ ❄️ '] | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | class EmojiParser(object): | ||||||
|  | 	def __init__(self, condition_text): | ||||||
|  | 		self.condition_expression = condition_text.lower() | ||||||
|  | 		self.severity = None | ||||||
|  | 		self.nouns = [] | ||||||
|  |  | ||||||
|  | 		self.weather_nouns = ['cleary sky', 'fair', 'cloudy', 'rain', 'rain showers', 'sleet', | ||||||
|  | 			'sleet showers', 'snow showers', 'thunder', 'snow'] | ||||||
|  | 		self.weather_adjectives = {'light': 0, 'normal': 1, 'heavy': 2} | ||||||
|  |  | ||||||
|  | 	def __str__(self): | ||||||
|  | 	 	return str([self.condition_expression, self.severity, self.nouns]) | ||||||
|  |  | ||||||
|  | 	# Splits and lowers the condition text for easier parsing | ||||||
|  | 	def splitCondition(self, condition): | ||||||
|  | 		return condition.split() | ||||||
|  |  | ||||||
|  | 	# Takes a input or uses condition_expression to find adjective in sentence | ||||||
|  | 	def findAdjective(self, sentence=None): | ||||||
|  | 		if sentence is None: | ||||||
|  | 			sentence = self.condition_expression | ||||||
|  |  | ||||||
|  | 		# Splits and iterates over each word in sentence | ||||||
|  | 		expression = self.splitCondition(sentence) | ||||||
|  | 		for word in expression: | ||||||
|  | 			if word in self.weather_adjectives: | ||||||
|  | 				# Return the word if matched with weather_adjectives | ||||||
|  | 				return word | ||||||
|  |  | ||||||
|  | 		return None | ||||||
|  |  | ||||||
|  | 	# Removes the first adjective in the a given sentence | ||||||
|  | 	def removeAdjective(self): | ||||||
|  | 		adjective = self.findAdjective() | ||||||
|  | 		if adjective:	# Adjective is not None | ||||||
|  | 			expression = self.splitCondition(self.condition_expression) | ||||||
|  | 			expression.remove(adjective) | ||||||
|  | 			return ' '.join(expression) | ||||||
|  | 		else: | ||||||
|  | 			return self.condition_expression | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	def severityValue(self): | ||||||
|  | 		adjective = self.findAdjective() | ||||||
|  |  | ||||||
|  | 		if adjective: | ||||||
|  | 			self.severity = self.weather_adjectives[adjective] | ||||||
|  | 		else: | ||||||
|  | 			self.severity = self.weather_adjectives['normal'] | ||||||
|  |  | ||||||
|  | 	def findWeatherTokens(self): | ||||||
|  | 		# If present removes the leading adjective | ||||||
|  | 		sentence = self.removeAdjective() | ||||||
|  | 		 | ||||||
|  | 		# If multiple tokens/weather_nouns split all between the 'and' | ||||||
|  | 		if 'and' in sentence: | ||||||
|  | 			self.nouns = sentence.split(' and ') | ||||||
|  | 		else: | ||||||
|  | 			self.nouns = [sentence] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	# Use the symbol_table to convert the forecast name to emoji | ||||||
|  | 	def emojify(self, noun): | ||||||
|  | 		return symbol_table[noun] | ||||||
|  |  | ||||||
|  | 	# Does as emojify above, but iterates over a list if multiple elements | ||||||
|  | 	def emojifyList(self, noun_list): | ||||||
|  | 		returnList = [] | ||||||
|  | 		 | ||||||
|  | 		# TODO use more like a map function? | ||||||
|  | 		for noun in noun_list: | ||||||
|  | 			returnList.append(self.emojify(noun)) | ||||||
|  |  | ||||||
|  | 		return '  '.join(returnList) | ||||||
|  |  | ||||||
|  | 	def findPrimaryForecast(self): | ||||||
|  | 		# Copies the contents not the refrence to the list | ||||||
|  | 		noun_list = list(self.nouns) | ||||||
|  | 		forecast = noun_list.pop(0) | ||||||
|  |  | ||||||
|  | 		# Translates to emoji once here instead of twice below | ||||||
|  | 		forecast_emoji = self.emojify(forecast) | ||||||
|  |  | ||||||
|  | 		if forecast in severity: | ||||||
|  | 			return ('%s %s' % (forecast_emoji, severity[forecast])) | ||||||
|  | 		else: | ||||||
|  | 			return forecast_emoji | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	# Trying to analyze the semantics of the condition text | ||||||
|  | 	def emojifyWeatherForecast(self): | ||||||
|  | 		# Finds the tokens/nouns of weather for the given input text and severity value | ||||||
|  | 		self.findWeatherTokens() | ||||||
|  | 		self.severityValue() | ||||||
|  |  | ||||||
|  | 		primary_forecast = self.findPrimaryForecast() | ||||||
|  | 		secondary_forecast = self.emojifyList(self.nouns[1:]) | ||||||
|  | 		 | ||||||
|  | 		return ('%s %s' % (primary_forecast, secondary_forecast)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	def convertSematicsToEmoji(self): | ||||||
|  | 		return self.emojifyWeatherForecast() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  | 	emojiParser = EmojiParser('Cloudy') | ||||||
|  | 	print(emojiParser.convertSematicsToEmoji()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == '__main__': | ||||||
|  | 	main() | ||||||
							
								
								
									
										40
									
								
								termWeather/loadingAnimation.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										40
									
								
								termWeather/loadingAnimation.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | #!/usr/bin/env python3.6 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # @Author: KevinMidboe | ||||||
|  | # @Date:   2017-07-30 13:53:38 | ||||||
|  | # @Last Modified by:   KevinMidboe | ||||||
|  | # @Last Modified time: 2017-07-30 13:53:46 | ||||||
|  |  | ||||||
|  | import itertools | ||||||
|  | from threading import Thread | ||||||
|  | from time import sleep | ||||||
|  | from sys import stdout | ||||||
|  |  | ||||||
|  | class LoadingAnimation(object): | ||||||
|  | 	def __init__(self): | ||||||
|  | 		self.done = False | ||||||
|  |  | ||||||
|  | 	def start(self): | ||||||
|  | 		t = Thread(target=self.animate) | ||||||
|  | 		t.start() | ||||||
|  |  | ||||||
|  | 	def animate(self): | ||||||
|  | 	    for c in itertools.cycle(['|', '/', '-', '\\']): | ||||||
|  | 	        if self.done: | ||||||
|  | 	            break | ||||||
|  | 	        stdout.write('\rFetching ' + c) | ||||||
|  | 	        stdout.flush() | ||||||
|  | 	        sleep(0.1) | ||||||
|  |  | ||||||
|  | 	def stop(self): | ||||||
|  | 		self.done = True | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  | 	loadingAnimation = LoadingAnimation() | ||||||
|  | 	loadingAnimation.start() | ||||||
|  | 	sleep(2) | ||||||
|  | 	loadingAnimation.stop() | ||||||
|  | 	stdout.write('\rTemp          \n') | ||||||
|  | 	 | ||||||
|  | if __name__ == '__main__': | ||||||
|  | 	main() | ||||||
							
								
								
									
										127
									
								
								termWeather/term_weather.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										127
									
								
								termWeather/term_weather.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,127 @@ | |||||||
|  | #!/usr/bin/env python3.6 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # @Author: KevinMidboe | ||||||
|  | # @Date:   2017-07-27 21:26:53 | ||||||
|  | # @Last Modified by:   KevinMidboe | ||||||
|  | # @Last Modified time: 2017-07-30 18:56:27 | ||||||
|  |  | ||||||
|  | # TODO LIST | ||||||
|  | # Get coordinates from IP ✔ | ||||||
|  | # Fetch coordinates from YR ✔ | ||||||
|  | # Convert coordinates to place name w/ google GeoCode api ✔ | ||||||
|  | # Parse return data | ||||||
|  | # Match weather description to icons ✔ | ||||||
|  | # Check internet connection in a strict way | ||||||
|  | # Add table for time periode | ||||||
|  | # Add cache for quicker location for same ip | ||||||
|  |  | ||||||
|  | import fire, json, geoip2.database, ssl, os | ||||||
|  | from yr.libyr import Yr | ||||||
|  | from requests import get | ||||||
|  | from pprint import pprint | ||||||
|  | from sys import stdout | ||||||
|  |  | ||||||
|  | from emojiParser import EmojiParser | ||||||
|  | from loadingAnimation import LoadingAnimation | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Location(object): | ||||||
|  | 	def __init__(self): | ||||||
|  |  | ||||||
|  | 		abspath = os.path.abspath(__file__) | ||||||
|  | 		dname = os.path.dirname(abspath) | ||||||
|  | 		os.chdir(dname) | ||||||
|  | 		self.reader = geoip2.database.Reader('conf/GeoLite2-City.mmdb') | ||||||
|  | 		self.getIP() | ||||||
|  |  | ||||||
|  | 	def getIP(self): | ||||||
|  | 		ip = get('https://api.ipify.org').text | ||||||
|  | 		self.ip = self.reader.city(ip) | ||||||
|  |  | ||||||
|  | 	def getCoordinates(self): | ||||||
|  | 		lat = self.ip.location.latitude | ||||||
|  | 		long = self.ip.location.longitude | ||||||
|  | 		return [lat, long] | ||||||
|  |  | ||||||
|  | 	def getAreaName(self): | ||||||
|  | 		lat, long = self.getCoordinates() | ||||||
|  | 		coordinates = ','.join([str(lat), str(long)]) | ||||||
|  | 		areaURL = 'https://maps.googleapis.com/maps/api/geocode/json?&latlng=' | ||||||
|  |  | ||||||
|  | 		areaAPIResponse = json.loads(get(areaURL + coordinates).text) | ||||||
|  | 		closestArea = areaAPIResponse['results'][0]['address_components'] | ||||||
|  |  | ||||||
|  | 		area = {} | ||||||
|  |  | ||||||
|  | 		for item in closestArea: | ||||||
|  | 			if 'route' in item['types']: | ||||||
|  | 				area['street'] = item['long_name'] | ||||||
|  |  | ||||||
|  | 			if 'locality' in item['types']: | ||||||
|  | 				area['town'] = item['long_name'] | ||||||
|  |  | ||||||
|  | 			if 'administrative_area_level_1' in item['types']: | ||||||
|  | 				area['municipality'] = item['long_name'] | ||||||
|  |  | ||||||
|  | 			if 'country' in item['types']: | ||||||
|  | 				area['country'] = item['long_name'] | ||||||
|  |  | ||||||
|  | 		return area | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class WeatherForecast(object): | ||||||
|  | 	def __init__(self, area=None): | ||||||
|  | 		# TODO search for area coordinates in a map | ||||||
|  | 		self.area = area | ||||||
|  |  | ||||||
|  | 		self.name = None | ||||||
|  | 		self.number = None | ||||||
|  | 		self.variable = None | ||||||
|  |  | ||||||
|  | 	def symbolVariables(self, symbol_obj): | ||||||
|  | 		self.name = symbol_obj['@name'] | ||||||
|  | 		self.number = symbol_obj['@number'] | ||||||
|  | 		self.variable = symbol_obj['@var'] | ||||||
|  |  | ||||||
|  | 	def parseYrTemperature(self, temperature_obj): | ||||||
|  | 		return temperature_obj['@value'] + ' ' + temperature_obj['@unit'] | ||||||
|  |  | ||||||
|  | 	def now(self): | ||||||
|  | 		location = Location() | ||||||
|  | 		self.area = location.getAreaName() | ||||||
|  |  | ||||||
|  | 		# Create seperate function for formatting | ||||||
|  | 		locationName = '/'.join([self.area['country'], self.area['municipality'], self.area['town'], self.area['street']]) | ||||||
|  |  | ||||||
|  | 		# Use the defined location name with yr API for location based weather information | ||||||
|  | 		weather = Yr(location_name=locationName) | ||||||
|  | 		now = json.loads(weather.now(as_json=True)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		temperature_output = self.parseYrTemperature(now['temperature']) | ||||||
|  |  | ||||||
|  | 		emojiParser = EmojiParser(now['symbol']['@name']) | ||||||
|  | 		weatherIcon_output = emojiParser.convertSematicsToEmoji() | ||||||
|  |  | ||||||
|  | 		return ('%s %s' % (temperature_output, weatherIcon_output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TermWeather(object): | ||||||
|  | 	# Add now, forecast as args | ||||||
|  | 	def auto(self): | ||||||
|  | 		loadingAnimation = LoadingAnimation() | ||||||
|  | 		loadingAnimation.start() | ||||||
|  | 		weatherForecast = WeatherForecast() | ||||||
|  | 		forecast = weatherForecast.now() | ||||||
|  | 		loadingAnimation.stop() | ||||||
|  | 		stdout.write('\r%s          \n' % forecast) | ||||||
|  |  | ||||||
|  | 	def fetch(self, area=None): | ||||||
|  | 		weatherForecast = WeatherForcast(area) | ||||||
|  | 		weatherForecast.now() | ||||||
|  | 		 | ||||||
|  |  | ||||||
|  | if __name__ == '__main__': | ||||||
|  | 	ssl._create_default_https_context = ssl._create_unverified_context | ||||||
|  | 	 | ||||||
|  | 	fire.Fire(TermWeather()) | ||||||
		Reference in New Issue
	
	Block a user