#!/usr/bin/env python # -*- coding: utf-8 -*- from importlib.resources import contents from Stats import Stats import configparser from lib.Network import Network from Jessi import ContentFile from Jessi import Contents import datetime import math import json import random import lib.MoonPhase as mp import os import re class NummericPronounce: Normal = 0 Year = 1 Time = 2 class Text: instance = None content = dict() @staticmethod def getInstance(): if Text.instance==None: Text.instance = Text() return Text.instance def __init__(self): self.stats:Stats = Stats.getInstance() self.config = configparser.ConfigParser() self.config.read("config/config.ini") self.replacer = list() # TODO: Replacer.js laden, und alle 60-180 Sekunden eine List-Variable mit möglichen Antworten füllen / aktualisieren # z.B. aus der Replacer.js "badwords" mit allen möglichen Antworten, abhängig der Requirements, in die Variable "replacer["badwords"][]" füllen # Weitere mögliche Wortlisten: "niceword" (incl cuteness, wenn verspieltheit hoch ist) self.readReplacer() def getText(self, intent:str, tags) -> Contents: if intent not in self.content: if os.path.isfile("ressources/texts/"+intent+".json") == False: print("Failed to load intent text: "+intent) return "" self.content[intent] = ContentFile.ContentFile(intent+".json") return self.content[intent].getText(tags) def executeText(self, intent:str, tags) -> str: if intent not in self.content: if os.path.isfile("ressources/texts/"+intent+".json") == False: print("Failed to load intent text: "+intent) return "" self.content[intent] = ContentFile.ContentFile(intent+".json") return self.formatText(self.content[intent].executeText(tags)) def formatText(self, text:str ) -> str: if text.find("{"): if text.find("{device."): text = text.replace("{device.name}",self.config["global"]["DeviceName"]) text = text.replace("{device.owner}",self.config["global"]["Owner"]) text = text.replace("{device.ip}", Network.getIp()) text = text.replace("{device.host}", Network.getHostName()) text = text.replace("{device.hostname}", Network.getHostName()) if text.find("{datetime."): #Tomorow: datetime.datetime.now() + datetime.timedelta(days=1) #Yesterday: datetime.datetime.now() - datetime.timedelta(days=1) text = self._formatText_DateTime(text,datetime.datetime.now(),"now") text = self._formatText_DateTime(text,datetime.datetime.now() + datetime.timedelta(days=1),"tomorow") text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"yesterday") text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"morning") #TODO text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"midday") #TODO text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"evening") #TODO text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"night") #TODO if text.find("{weather."): pass if text.find("{house."): pass if text.find("{event."): pass if text.find("{calender."): pass if text.find("{"): print("Enter Replacer Loop") deadcounter=0 for k in self.replacer: print("- Search for '"+k+"'") notfound=False while notfound==False: if text.find("{"+k+"|") >= 0: print("- found {"+k+"|") word = self.getRandomWord(self.replacer[k]) if word=="": text = re.sub("\\{"+k+"(?:\\|([a-z]{0,5}))?\\}","",text,1) else: text = re.sub("\\{"+k+"(?:\\|([a-z]{0,5}))?\\}",word+"\\1",text,1) #pos1 = text.find("{"+k+"|") #pos2 = pos1 + 2 + len(k) #pos3 = text.find("}",pos1) #res = text[0:pos1] + word + text[pos2:pos3-pos2] + text[pos3:] #text=res elif text.find("{"+k+"}") >= 0: print("- found {"+k+"}") text = re.sub("\\{"+k+"\\}",self.getRandomWord(self.replacer[k]),text,1) else: notfound=True break deadcounter+=1 if deadcounter > 40: break print("Exit Replacer Loop") return text def _formatText_DateTime(self,text:str,dt:datetime.datetime,name:str): name="{datetime."+name+"." if text.find(name): dt = datetime.datetime.now() + datetime.timedelta(days=1) text = text.replace(name+"weekday}", self.getWeekDay(dt.weekday()) ) text = text.replace(name+"year}", self.getNumericPronounce(dt.year,0, NummericPronounce.Year) ) text = text.replace(name+"month}", self.getMonthName(dt.month) ) text = text.replace(name+"day}", self.getNumericDottedPronounce(dt.day) ) text = text.replace(name+"hour}", self.getNumericPronounce(dt.hour) ) text = text.replace(name+"minute}", self.getNumericPronounce(dt.minute) ) text = text.replace(name+"seconds}", self.getNumericPronounce(dt.second) ) text = text.replace(name+"second}", self.getNumericPronounce(dt.second) ) text = text.replace(name+"}", self.getDateString(dt) ) text = text.replace(name+"moonphase}", mp.phase(time=dt)["name"] ) return text def getRandomWord(self, items:list) -> str: if len(items) > 0: return random.choice(items) else: return "" def readReplacer(self): tmp = {} with open("ressources/texts/Replacer.json", encoding="utf-8") as json_file: data = json.load(json_file) for k in data: tmp[k] = list() add = True for i in data[k]: if "mood_required" in i: statKeys = ["angry","annoyed","aroused","bored","compfortable","depressive","energy","excited","exhausted", "freezy","funny","happyness","hot","humanity","hungry","intelligent","irritated","lonely","naiv", "playful","sad","shy","sleepy","soziality","temperate","toLoud","toQuiet","usefull","useless"] for sk in statKeys: if sk+"_max" in i["mood_required"] and i["mood_required"][sk+"_max"] <= getattr(self.stats.DeviceStats,sk): add = False break if sk+"_min" in i["mood_required"] and i["mood_required"][sk+"_min"] >= getattr(self.stats.DeviceStats,sk): add = False break if add == True and "text" in i: for t in i["text"]: tmp[k].append(t) self.replacer = tmp @staticmethod def getWeekDay(weekday:int) -> str: weekdays = [ "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" ] return weekdays[weekday] @staticmethod def getMonthName(month:int) -> str: monthnames = [ "", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" ] return monthnames[month] @staticmethod def getNumericPronounce(num:float, decimals:int = 2, type:int = NummericPronounce.Normal) -> str: ''' Formats a integer or floating point value into a readable string num:float - The Number that should be writeable decimals:int - the amount of decimals (max 6) Range: -999,999,999.999999 to 999,999,999.999999 Returns :str''' if type == NummericPronounce.Year: s2="" if num<0: num*=-1 s2=" vor Christus" if num>=1300 and num<2200: num3 = math.floor(num/100) s = Text.getNumericPronounce(num3) num2 = num % 100 if(num2>9): s += " " + Text.getNumericPronounce(num2) else: s += " null " + Text.getNumericPronounce(num2 % 10) return s+s2 else: # Check for negative numbers if num<0: return "Minus " + Text.getNumericPronounce(num * -1) # Check for decimal if math.floor(num)!=math.ceil(num): if decimals<1: num=math.floor(num) else: s = Text.getNumericPronounce(math.floor(num)) num -= math.floor(num) s+=" Komma" s+= " " + Text.getNumericPronounce(math.floor(num*10)%10) if decimals>=2: s+= " " + Text.getNumericPronounce(math.floor(num*100)%10) if decimals>=3: s+= " " + Text.getNumericPronounce(math.floor(num*1000)%10) if decimals>=4: s+= " " + Text.getNumericPronounce(math.floor(num*10000)%10) if decimals>=5: s+= " " + Text.getNumericPronounce(math.floor(num*100000)%10) if decimals>=6: s+= " " + Text.getNumericPronounce(math.floor(num*1000000)%10) return s mod = num%10 zehner=(num-mod) % 100 hunderter=(num-mod-zehner) % 1000 tausender=(num-mod-zehner-hunderter) % 1000000 millonener=(num-mod-zehner-hunderter-tausender) % 1000000000 if num==0: return "null" elif num==1: return "eins" # handels 1 only elif num==2: return "zwei" # handels 2, 200, 302, 2.000, 2.000.000 elif num==3: return "drei" elif num==4: return "vier" elif num==5: return "fünf" elif num==6: return "sechs" elif num==7: return "sieben" elif num==8: return "acht" elif num==9: return "neun" elif num==10: return "zehn" elif num==11: return "elf" elif num==12: return "zwölf" elif num<=19: return Text.getNumericPronounce(mod)+"zehn" elif num==20: return "zwanzig" elif num==30: return "dreissig" elif num==60: return "sechzig" elif num==70: return "siebzig" elif num<=99 and mod == 0: return Text.getNumericPronounce(zehner/10)+"zig" elif num<=99 and mod == 1: return "einund"+Text.getNumericPronounce(zehner) # handels 21, 31, 41, 51, ... elif num<=99 and mod > 1: return Text.getNumericPronounce(mod) + "und"+ Text.getNumericPronounce(zehner) #handels 22, 23, 24, 25, ... 32, 33, 34, ..., 42, 53, .... elif num==100: return "einhundert" # handels 100 elif num<=199: return "einhundert" + Text.getNumericPronounce(num%100) # handels 101, 102, 103, ... elif num<=999 and num%100==0: return Text.getNumericPronounce(hunderter/100)+"hundert" # handels 200, 300, 400, 500, 600, 700, 800, 900 elif num<=999: return Text.getNumericPronounce(hunderter/100)+"hundert"+Text.getNumericPronounce(num%100) # handels 201, 202, ... 301, 302 elif num==1000: return "eintausend" elif num==10000: return "zehntausend" elif num==100000: return "einhunderttausend" elif num==1000000: return "eine millionen" elif num<=1999: return "eintausend"+Text.getNumericPronounce(num%1000) elif num<=999999 and num%1000==0: return Text.getNumericPronounce(tausender/1000)+"tausend" # handels 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000 elif num<=999999: return Text.getNumericPronounce(tausender/1000)+"tausend "+Text.getNumericPronounce(num%1000) elif num<=1999999: return "eine millionen "+Text.getNumericPronounce(millonener%1000000) elif num<=999999999 and num%1000000==0: return Text.getNumericPronounce(millonener/1000000)+" millionen" # handels 2mio, 3mio, 4mio, 5mio, 6mio, 7mio, 8mio, 9mio elif num<=999999999: return Text.getNumericPronounce(millonener/1000000)+" millionen "+Text.getNumericPronounce(num%1000000) else: print("ErrNum: "+num) @staticmethod def getNumericDottedPronounce(num:int) -> str: if num==1: return "erste" elif num==3: return "dritte" elif num==8: return "achte" elif num>= 20: return Text.getNumericPronounce(num)+"ste" else: return Text.getNumericPronounce(num)+"te" @staticmethod def getDateString(date, WeekDay:bool = True, Year:bool = True) -> str: if WeekDay and Year: return Text.getWeekDay(date.weekday())+", der "+Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month)+" "+Text.getNumericPronounce(date.year, 0, NummericPronounce.Year) pass elif WeekDay: return Text.getWeekDay(date.weekday())+", der "+Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month) elif Year: return Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month)+" "+Text.getNumericPronounce(date.year, 0, NummericPronounce.Year) else: return Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month) @staticmethod def getTimeString(time, Seconds:bool=False, Use24:bool=False) -> str: if Seconds: return Text.getTimeString(time,False,Use24)+" und " + time.seconds+" Sekunden" else: min = time.minute sur="" surn="" if Use24: hour=Text.getNumericPronounce(time.hour) hourn=Text.getNumericPronounce((time.hour+1)%24) else: hour=Text.getNumericPronounce(time.hour%12) hourn=Text.getNumericPronounce((time.hour+1)%12) if time.hour<5 or time.hour>21: sur=" Nachts" elif time.hour<11: sur=" Morgens" elif time.hour<16: sur=" Mittags" elif time.hour<19: sur=" Nachmittags" else: sur=" Abends" if time.hour<4 or time.hour>20: surn=" Nachts" elif time.hour<10: surn=" Morgens" elif time.hour<15: surn=" Mittags" elif time.hour<18: surn=" Nachmittags" else: surn=" Abends" if time.hour==23: shour=hour shourn="Mitternacht" elif time==0: shour="Mitternacht" shourn=hourn else: shour=hour shourn=hourn if min==0: return "punkt "+shour+sur elif min==30: return "halb "+shourn+surn elif min>=27 and min<30: return "kurz vor halb "+shourn+surn elif min>30 and min<=33: return "kurz nach halb "+shourn+surn elif min==15: return "viertel nach "+shour+sur elif min==45: return "viertel vor "+shourn+surn elif min<=3: return "kurz nach "+shour+sur elif min>=37: return "kurz vor "+shourn+surn else: return hour+" Uhr "+Text.getNumericPronounce(min)+sur