PageRenderTime 64ms CodeModel.GetById 20ms app.highlight 22ms RepoModel.GetById 18ms app.codeStats 0ms

/modules/calc.py

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