main.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from importlib.resources import contents
  4. from Stats import Stats
  5. import configparser
  6. from lib.Network import Network
  7. from Jessi import ContentFile
  8. from Jessi import Contents
  9. import datetime
  10. import math
  11. import json
  12. import random
  13. import lib.MoonPhase as mp
  14. import os
  15. import re
  16. class NummericPronounce:
  17. Normal = 0
  18. Year = 1
  19. Time = 2
  20. class Text:
  21. instance = None
  22. content = dict()
  23. @staticmethod
  24. def getInstance():
  25. if Text.instance==None:
  26. Text.instance = Text()
  27. return Text.instance
  28. def __init__(self):
  29. self.stats:Stats = Stats.getInstance()
  30. self.config = configparser.ConfigParser()
  31. self.config.read("config/config.ini")
  32. self.replacer = list()
  33. # TODO: Replacer.js laden, und alle 60-180 Sekunden eine List-Variable mit möglichen Antworten füllen / aktualisieren
  34. # z.B. aus der Replacer.js "badwords" mit allen möglichen Antworten, abhängig der Requirements, in die Variable "replacer["badwords"][]" füllen
  35. # Weitere mögliche Wortlisten: "niceword" (incl cuteness, wenn verspieltheit hoch ist)
  36. self.readReplacer()
  37. def getText(self, intent:str, tags) -> Contents:
  38. if intent not in self.content:
  39. if os.path.isfile("ressources/texts/"+intent+".json") == False:
  40. print("Failed to load intent text: "+intent)
  41. return ""
  42. self.content[intent] = ContentFile.ContentFile(intent+".json")
  43. return self.content[intent].getText(tags)
  44. def executeText(self, intent:str, tags) -> str:
  45. if intent not in self.content:
  46. if os.path.isfile("ressources/texts/"+intent+".json") == False:
  47. print("Failed to load intent text: "+intent)
  48. return ""
  49. self.content[intent] = ContentFile.ContentFile(intent+".json")
  50. return self.formatText(self.content[intent].executeText(tags))
  51. def formatText(self, text:str ) -> str:
  52. if text.find("{"):
  53. if text.find("{device."):
  54. text = text.replace("{device.name}",self.config["global"]["DeviceName"])
  55. text = text.replace("{device.owner}",self.config["global"]["Owner"])
  56. text = text.replace("{device.ip}", Network.getIp())
  57. text = text.replace("{device.host}", Network.getHostName())
  58. text = text.replace("{device.hostname}", Network.getHostName())
  59. if text.find("{datetime."):
  60. #Tomorow: datetime.datetime.now() + datetime.timedelta(days=1)
  61. #Yesterday: datetime.datetime.now() - datetime.timedelta(days=1)
  62. text = self._formatText_DateTime(text,datetime.datetime.now(),"now")
  63. text = self._formatText_DateTime(text,datetime.datetime.now() + datetime.timedelta(days=1),"tomorow")
  64. text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"yesterday")
  65. text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"morning") #TODO
  66. text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"midday") #TODO
  67. text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"evening") #TODO
  68. text = self._formatText_DateTime(text,datetime.datetime.now() - datetime.timedelta(days=1),"night") #TODO
  69. if text.find("{weather."):
  70. pass
  71. if text.find("{house."):
  72. pass
  73. if text.find("{event."):
  74. pass
  75. if text.find("{calender."):
  76. pass
  77. if text.find("{"):
  78. print("Enter Replacer Loop")
  79. deadcounter=0
  80. for k in self.replacer:
  81. print("- Search for '"+k+"'")
  82. notfound=False
  83. while notfound==False:
  84. if text.find("{"+k+"|") >= 0:
  85. print("- found {"+k+"|")
  86. word = self.getRandomWord(self.replacer[k])
  87. if word=="":
  88. text = re.sub("\\{"+k+"(?:\\|([a-z]{0,5}))?\\}","",text,1)
  89. else:
  90. text = re.sub("\\{"+k+"(?:\\|([a-z]{0,5}))?\\}",word+"\\1",text,1)
  91. #pos1 = text.find("{"+k+"|")
  92. #pos2 = pos1 + 2 + len(k)
  93. #pos3 = text.find("}",pos1)
  94. #res = text[0:pos1] + word + text[pos2:pos3-pos2] + text[pos3:]
  95. #text=res
  96. elif text.find("{"+k+"}") >= 0:
  97. print("- found {"+k+"}")
  98. text = re.sub("\\{"+k+"\\}",self.getRandomWord(self.replacer[k]),text,1)
  99. else:
  100. notfound=True
  101. break
  102. deadcounter+=1
  103. if deadcounter > 40:
  104. break
  105. print("Exit Replacer Loop")
  106. return text
  107. def _formatText_DateTime(self,text:str,dt:datetime.datetime,name:str):
  108. name="{datetime."+name+"."
  109. if text.find(name):
  110. dt = datetime.datetime.now() + datetime.timedelta(days=1)
  111. text = text.replace(name+"weekday}", self.getWeekDay(dt.weekday()) )
  112. text = text.replace(name+"year}", self.getNumericPronounce(dt.year,0, NummericPronounce.Year) )
  113. text = text.replace(name+"month}", self.getMonthName(dt.month) )
  114. text = text.replace(name+"day}", self.getNumericDottedPronounce(dt.day) )
  115. text = text.replace(name+"hour}", self.getNumericPronounce(dt.hour) )
  116. text = text.replace(name+"minute}", self.getNumericPronounce(dt.minute) )
  117. text = text.replace(name+"seconds}", self.getNumericPronounce(dt.second) )
  118. text = text.replace(name+"second}", self.getNumericPronounce(dt.second) )
  119. text = text.replace(name+"}", self.getDateString(dt) )
  120. text = text.replace(name+"moonphase}", mp.phase(time=dt)["name"] )
  121. return text
  122. def getRandomWord(self, items:list) -> str:
  123. if len(items) > 0:
  124. return random.choice(items)
  125. else:
  126. return ""
  127. def readReplacer(self):
  128. tmp = {}
  129. with open("ressources/texts/Replacer.json", encoding="utf-8") as json_file:
  130. data = json.load(json_file)
  131. for k in data:
  132. tmp[k] = list()
  133. add = True
  134. for i in data[k]:
  135. if "mood_required" in i:
  136. statKeys = ["angry","annoyed","aroused","bored","compfortable","depressive","energy","excited","exhausted",
  137. "freezy","funny","happyness","hot","humanity","hungry","intelligent","irritated","lonely","naiv",
  138. "playful","sad","shy","sleepy","soziality","temperate","toLoud","toQuiet","usefull","useless"]
  139. for sk in statKeys:
  140. if sk+"_max" in i["mood_required"] and i["mood_required"][sk+"_max"] <= getattr(self.stats.DeviceStats,sk):
  141. add = False
  142. break
  143. if sk+"_min" in i["mood_required"] and i["mood_required"][sk+"_min"] >= getattr(self.stats.DeviceStats,sk):
  144. add = False
  145. break
  146. if add == True and "text" in i:
  147. for t in i["text"]:
  148. tmp[k].append(t)
  149. self.replacer = tmp
  150. @staticmethod
  151. def getWeekDay(weekday:int) -> str:
  152. weekdays = [
  153. "Sonntag",
  154. "Montag",
  155. "Dienstag",
  156. "Mittwoch",
  157. "Donnerstag",
  158. "Freitag",
  159. "Samstag",
  160. "Sonntag"
  161. ]
  162. return weekdays[weekday]
  163. @staticmethod
  164. def getMonthName(month:int) -> str:
  165. monthnames = [
  166. "",
  167. "Januar",
  168. "Februar",
  169. "März",
  170. "April",
  171. "Mai",
  172. "Juni",
  173. "Juli",
  174. "August",
  175. "September",
  176. "Oktober",
  177. "November",
  178. "Dezember"
  179. ]
  180. return monthnames[month]
  181. @staticmethod
  182. def getNumericPronounce(num:float, decimals:int = 2, type:int = NummericPronounce.Normal) -> str:
  183. ''' Formats a integer or floating point value into a readable string
  184. num:float - The Number that should be writeable
  185. decimals:int - the amount of decimals (max 6)
  186. Range: -999,999,999.999999 to 999,999,999.999999
  187. Returns :str'''
  188. if type == NummericPronounce.Year:
  189. s2=""
  190. if num<0:
  191. num*=-1
  192. s2=" vor Christus"
  193. if num>=1300 and num<2200:
  194. num3 = math.floor(num/100)
  195. s = Text.getNumericPronounce(num3)
  196. num2 = num % 100
  197. if(num2>9):
  198. s += " " + Text.getNumericPronounce(num2)
  199. else:
  200. s += " null " + Text.getNumericPronounce(num2 % 10)
  201. return s+s2
  202. else:
  203. # Check for negative numbers
  204. if num<0:
  205. return "Minus " + Text.getNumericPronounce(num * -1)
  206. # Check for decimal
  207. if math.floor(num)!=math.ceil(num):
  208. if decimals<1:
  209. num=math.floor(num)
  210. else:
  211. s = Text.getNumericPronounce(math.floor(num))
  212. num -= math.floor(num)
  213. s+=" Komma"
  214. s+= " " + Text.getNumericPronounce(math.floor(num*10)%10)
  215. if decimals>=2: s+= " " + Text.getNumericPronounce(math.floor(num*100)%10)
  216. if decimals>=3: s+= " " + Text.getNumericPronounce(math.floor(num*1000)%10)
  217. if decimals>=4: s+= " " + Text.getNumericPronounce(math.floor(num*10000)%10)
  218. if decimals>=5: s+= " " + Text.getNumericPronounce(math.floor(num*100000)%10)
  219. if decimals>=6: s+= " " + Text.getNumericPronounce(math.floor(num*1000000)%10)
  220. return s
  221. mod = num%10
  222. zehner=(num-mod) % 100
  223. hunderter=(num-mod-zehner) % 1000
  224. tausender=(num-mod-zehner-hunderter) % 1000000
  225. millonener=(num-mod-zehner-hunderter-tausender) % 1000000000
  226. if num==0: return "null"
  227. elif num==1: return "eins" # handels 1 only
  228. elif num==2: return "zwei" # handels 2, 200, 302, 2.000, 2.000.000
  229. elif num==3: return "drei"
  230. elif num==4: return "vier"
  231. elif num==5: return "fünf"
  232. elif num==6: return "sechs"
  233. elif num==7: return "sieben"
  234. elif num==8: return "acht"
  235. elif num==9: return "neun"
  236. elif num==10: return "zehn"
  237. elif num==11: return "elf"
  238. elif num==12: return "zwölf"
  239. elif num<=19: return Text.getNumericPronounce(mod)+"zehn"
  240. elif num==20: return "zwanzig"
  241. elif num==30: return "dreissig"
  242. elif num==60: return "sechzig"
  243. elif num==70: return "siebzig"
  244. elif num<=99 and mod == 0: return Text.getNumericPronounce(zehner/10)+"zig"
  245. elif num<=99 and mod == 1: return "einund"+Text.getNumericPronounce(zehner) # handels 21, 31, 41, 51, ...
  246. elif num<=99 and mod > 1: return Text.getNumericPronounce(mod) + "und"+ Text.getNumericPronounce(zehner) #handels 22, 23, 24, 25, ... 32, 33, 34, ..., 42, 53, ....
  247. elif num==100: return "einhundert" # handels 100
  248. elif num<=199: return "einhundert" + Text.getNumericPronounce(num%100) # handels 101, 102, 103, ...
  249. elif num<=999 and num%100==0: return Text.getNumericPronounce(hunderter/100)+"hundert" # handels 200, 300, 400, 500, 600, 700, 800, 900
  250. elif num<=999: return Text.getNumericPronounce(hunderter/100)+"hundert"+Text.getNumericPronounce(num%100) # handels 201, 202, ... 301, 302
  251. elif num==1000: return "eintausend"
  252. elif num==10000: return "zehntausend"
  253. elif num==100000: return "einhunderttausend"
  254. elif num==1000000: return "eine millionen"
  255. elif num<=1999: return "eintausend"+Text.getNumericPronounce(num%1000)
  256. elif num<=999999 and num%1000==0: return Text.getNumericPronounce(tausender/1000)+"tausend" # handels 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000
  257. elif num<=999999: return Text.getNumericPronounce(tausender/1000)+"tausend "+Text.getNumericPronounce(num%1000)
  258. elif num<=1999999: return "eine millionen "+Text.getNumericPronounce(millonener%1000000)
  259. elif num<=999999999 and num%1000000==0: return Text.getNumericPronounce(millonener/1000000)+" millionen" # handels 2mio, 3mio, 4mio, 5mio, 6mio, 7mio, 8mio, 9mio
  260. elif num<=999999999: return Text.getNumericPronounce(millonener/1000000)+" millionen "+Text.getNumericPronounce(num%1000000)
  261. else: print("ErrNum: "+num)
  262. @staticmethod
  263. def getNumericDottedPronounce(num:int) -> str:
  264. if num==1:
  265. return "erste"
  266. elif num==3:
  267. return "dritte"
  268. elif num==8:
  269. return "achte"
  270. elif num>= 20:
  271. return Text.getNumericPronounce(num)+"ste"
  272. else:
  273. return Text.getNumericPronounce(num)+"te"
  274. @staticmethod
  275. def getDateString(date, WeekDay:bool = True, Year:bool = True) -> str:
  276. if WeekDay and Year:
  277. return Text.getWeekDay(date.weekday())+", der "+Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month)+" "+Text.getNumericPronounce(date.year, 0, NummericPronounce.Year)
  278. pass
  279. elif WeekDay:
  280. return Text.getWeekDay(date.weekday())+", der "+Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month)
  281. elif Year:
  282. return Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month)+" "+Text.getNumericPronounce(date.year, 0, NummericPronounce.Year)
  283. else:
  284. return Text.getNumericDottedPronounce(date.day)+" "+Text.getMonthName(date.month)
  285. @staticmethod
  286. def getTimeString(time, Seconds:bool=False, Use24:bool=False) -> str:
  287. if Seconds:
  288. return Text.getTimeString(time,False,Use24)+" und " + time.seconds+" Sekunden"
  289. else:
  290. min = time.minute
  291. sur=""
  292. surn=""
  293. if Use24:
  294. hour=Text.getNumericPronounce(time.hour)
  295. hourn=Text.getNumericPronounce((time.hour+1)%24)
  296. else:
  297. hour=Text.getNumericPronounce(time.hour%12)
  298. hourn=Text.getNumericPronounce((time.hour+1)%12)
  299. if time.hour<5 or time.hour>21: sur=" Nachts"
  300. elif time.hour<11: sur=" Morgens"
  301. elif time.hour<16: sur=" Mittags"
  302. elif time.hour<19: sur=" Nachmittags"
  303. else: sur=" Abends"
  304. if time.hour<4 or time.hour>20: surn=" Nachts"
  305. elif time.hour<10: surn=" Morgens"
  306. elif time.hour<15: surn=" Mittags"
  307. elif time.hour<18: surn=" Nachmittags"
  308. else: surn=" Abends"
  309. if time.hour==23:
  310. shour=hour
  311. shourn="Mitternacht"
  312. elif time==0:
  313. shour="Mitternacht"
  314. shourn=hourn
  315. else:
  316. shour=hour
  317. shourn=hourn
  318. if min==0:
  319. return "punkt "+shour+sur
  320. elif min==30:
  321. return "halb "+shourn+surn
  322. elif min>=27 and min<30:
  323. return "kurz vor halb "+shourn+surn
  324. elif min>30 and min<=33:
  325. return "kurz nach halb "+shourn+surn
  326. elif min==15:
  327. return "viertel nach "+shour+sur
  328. elif min==45:
  329. return "viertel vor "+shourn+surn
  330. elif min<=3:
  331. return "kurz nach "+shour+sur
  332. elif min>=37:
  333. return "kurz vor "+shourn+surn
  334. else:
  335. return hour+" Uhr "+Text.getNumericPronounce(min)+sur