PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/calc.py

https://github.com/myano/jenni
Python | 256 lines | 214 code | 16 blank | 26 comment | 17 complexity | 0c634e9947d10446e1f2943282c4eabb MD5 | raw file
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. """
  4. calc.py - jenni Calculator Module
  5. Copyright 2009-2013, yano (yanovich.net)
  6. Copyright 2008-2013, Sean B. Palmer (inamidst.com)
  7. Licensed under the Eiffel Forum License 2.
  8. More info:
  9. * jenni: https://github.com/myano/jenni/
  10. * Phenny: http://inamidst.com/phenny/
  11. """
  12. import HTMLParser
  13. import json
  14. import re
  15. import string
  16. import urllib
  17. import web
  18. from modules import unicode as uc
  19. c_pattern = r'(?ims)<(?:h2 class="r"|div id="aoba")[^>]*>(.*?)</(?:h2|div)>'
  20. c_answer = re.compile(c_pattern)
  21. r_tag = re.compile(r'<(?!!)[^>]+>')
  22. WAKEY_NOTFOUND = "Please sign up for WolframAlpha's API to use this function. http://products.wolframalpha.com/api/"
  23. try:
  24. from modules import proxy
  25. except:
  26. pass
  27. def clean_up_answer(answer):
  28. answer = answer.encode('utf-8')
  29. answer = answer.decode('utf-8')
  30. answer = ''.join(chr(ord(c)) for c in answer)
  31. answer = uc.decode(answer)
  32. answer = answer.replace('<sup>', '^(')
  33. answer = answer.replace('</sup>', ')')
  34. answer = web.decode(answer)
  35. answer = answer.strip()
  36. answer += ' [GC]'
  37. return answer
  38. def c(jenni, input):
  39. '''.c -- Google calculator.'''
  40. ## let's not bother if someone doesn't give us input
  41. if not input.group(2):
  42. return jenni.reply('Nothing to calculate.')
  43. ## handle some unicode conversions
  44. q = input.group(2).encode('utf-8')
  45. q = q.replace('\xcf\x95', 'phi') # utf-8 U+03D5
  46. q = q.replace('\xcf\x80', 'pi') # utf-8 U+03C0
  47. temp_q = q.replace(' ', '')
  48. ## Attempt #1 (Google)
  49. uri_base = 'https://www.google.com/search?gbv=1&q='
  50. uri = uri_base + web.urllib.quote(temp_q)
  51. ## To the webs!
  52. page = str()
  53. try:
  54. page = proxy.get(uri)
  55. except:
  56. ## if we can't access Google for calculating
  57. ## let us try with good ole' web.get
  58. page = web.get(uri)
  59. answer = False
  60. if page:
  61. ## if we get a response from Google
  62. ## let us parse out an equation from Google Search results
  63. answer = c_answer.findall(page)
  64. if answer:
  65. ## if the regex finding found a match we want the first result
  66. answer = answer[0]
  67. answer = clean_up_answer(answer)
  68. jenni.say(answer)
  69. else:
  70. #### Attempt #1a
  71. uri = uri_base + web.urllib.quote(q)
  72. try:
  73. page = proxy.get(uri)
  74. except:
  75. page = web.get(uri)
  76. answer = False
  77. if page:
  78. answer = c_answer.findall(page)
  79. if answer:
  80. answer = answer[0]
  81. answer = clean_up_answer(answer)
  82. jenni.say(answer)
  83. else:
  84. #### Attempt #2 (DuckDuckGo's API)
  85. ddg_uri = 'https://api.duckduckgo.com/?format=json&q='
  86. ddg_uri += urllib.quote(q)
  87. ## Try to grab page (results)
  88. ## If page can't be accessed, we shall fail!
  89. try:
  90. page = proxy.get(ddg_uri)
  91. except:
  92. page = web.get(ddg_uri)
  93. ## Try to take page source and json-ify it!
  94. try:
  95. json_response = json.loads(page)
  96. except:
  97. ## if it can't be json-ified, then we shall fail!
  98. json_response = None
  99. ## Check for 'AnswerType' (stolen from search.py)
  100. ## Also 'fail' to None so we can move on to Attempt #3
  101. if (not json_response) or (hasattr(json_response, 'AnswerType') and json_response['AnswerType'] != 'calc'):
  102. answer = None
  103. else:
  104. ## If the json contains an Answer that is the result of 'calc'
  105. ## then continue
  106. answer = json_response['Answer']
  107. if hasattr(answer, 'result'):
  108. answer = answer['result']
  109. parts = answer.split('</style>')
  110. answer = ''.join(parts[1:])
  111. answer = re.sub(r'<.*?>', '', answer).strip()
  112. if answer:
  113. ## If we have found answer with Attempt #2
  114. ## go ahead and display it
  115. answer += ' [DDG API]'
  116. return jenni.say(answer)
  117. else:
  118. #### Attempt #3 (Wolfram Alpha)
  119. if not hasattr(jenni.config, 'wolframalpha_apikey'):
  120. return jenni.say(WAKEY_NOTFOUND)
  121. answer = get_wa(q, jenni.config.wolframalpha_apikey)
  122. return jenni.say(answer + ' [WA]')
  123. c.commands = ['c', 'cal', 'calc']
  124. c.example = '.c 5 + 3'
  125. def py(jenni, input):
  126. """.py <code> -- evaluates python code"""
  127. code = input.group(2)
  128. if not code:
  129. return jenni.reply('No code provided.')
  130. query = code.encode('utf-8')
  131. uri = 'https://tumbolia-two.appspot.com/py/'
  132. try:
  133. answer = web.get(uri + web.urllib.quote(query))
  134. if answer is not None and answer != "\n":
  135. jenni.say(answer)
  136. else:
  137. jenni.reply('Sorry, no result.')
  138. except Exception, e:
  139. jenni.reply('The server did not return an answer.')
  140. py.commands = ['py', 'python']
  141. py.example = '.py print "Hello world, %s!" % ("James")'
  142. def math(jenni, input):
  143. if not input.group(2):
  144. return jenni.reply("No search term.")
  145. txt = input.group(2)
  146. txt = txt.encode('utf-8')
  147. txt = txt.decode('utf-8')
  148. txt = txt.encode('utf-8')
  149. txt = urllib.quote(txt.replace('+', '%2B'))
  150. url = 'http://gamma.sympy.org/input/?i='
  151. re_answer = re.compile(r'<script type="\S+; mode=display".*?>(.*?)</script>')
  152. page = proxy.get(url + txt)
  153. results = re_answer.findall(page)
  154. if results:
  155. jenni.say(results[0])
  156. else:
  157. jenni.say('No results found on gamma.sympy.org!')
  158. math.commands = ['math']
  159. def get_wa(search, appid):
  160. txt = search
  161. txt = txt.decode('utf-8')
  162. txt = txt.encode('utf-8')
  163. txt = urllib.quote(txt)
  164. uri = 'https://api.wolframalpha.com/v2/query?reinterpret=true&appid=' + appid
  165. uri += '&input=' + txt
  166. page = web.get(uri)
  167. try:
  168. from bs4 import BeautifulSoup
  169. except ImportError:
  170. return "Please install 'bs4', also known as BeautifulSoup via pip to use WolframAlpha."
  171. soup = BeautifulSoup(page, 'xml')
  172. attempt_one = soup.find_all(attrs={'primary':'true'})
  173. answer = 'No answers found!'
  174. if attempt_one:
  175. answer = attempt_one[0].plaintext.get_text()
  176. if not answer:
  177. answer = attempt_one[0].imagesource.get_text()
  178. else:
  179. for pod in soup.find_all('pod'):
  180. if pod.get('title') != 'Input interpretation' and pod.plaintext.get_text():
  181. answer = pod.plaintext.get_text()
  182. break
  183. return answer
  184. def wa(jenni, input):
  185. if not hasattr(jenni.config, 'wolframalpha_apikey'):
  186. return jenni.say(WAKEY_NOTFOUND)
  187. appid = jenni.config.wolframalpha_apikey
  188. if not input.group(2):
  189. return jenni.reply("No search term.")
  190. txt = input.group(2)
  191. txt = txt.encode('utf-8')
  192. txt = txt.decode('utf-8')
  193. txt = txt.encode('utf-8')
  194. result = get_wa(txt, appid)
  195. if not result:
  196. return jenni.say("No results found.")
  197. return jenni.say(result)
  198. wa.commands = ['wa']
  199. if __name__ == '__main__':
  200. print __doc__.strip()