From a86066c386ad30a3b4210b0d732baabcf6ca7373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20H=C3=B6nig?= Date: Sun, 25 Dec 2016 16:20:05 +0000 Subject: [PATCH] interactive bots: Create converter bot. --- contrib_bots/lib/ConverterBot/docs.md | 70 +++++ .../lib/ConverterBot/multiple-converts.png | Bin 0 -> 54989 bytes contrib_bots/lib/converter.py | 275 ++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 contrib_bots/lib/ConverterBot/docs.md create mode 100644 contrib_bots/lib/ConverterBot/multiple-converts.png create mode 100644 contrib_bots/lib/converter.py diff --git a/contrib_bots/lib/ConverterBot/docs.md b/contrib_bots/lib/ConverterBot/docs.md new file mode 100644 index 0000000..252b836 --- /dev/null +++ b/contrib_bots/lib/ConverterBot/docs.md @@ -0,0 +1,70 @@ +# Converter bot + +This bot allows users to perform conversions for various measurement units. + +## Usage + +Run this bot as described in [here](http://zulip.readthedocs.io/en/latest/bots-guide.html#how-to-deploy-a-bot). + +Use this bot with the following command + +`@convert ` + +This will convert `number`, given in the unit `unit_from`, to the unit `unit_to` +and print the result. + +* `number` can be any floating-point number, e.g. 12, 13.05, 0.002. +* `unit_from` and `unit_to` are two units from [the following](#supported-units) table in the same category. +* `unit_from` and `unit_to` can be preceded by [these](#supported-prefixes) prefixes. + +### Supported units + +| Category | Units | +| ----------------- | ----- | +| Area | square-centimeter (cm^2, cm2), square-decimeter (dm^2, dm2), square-meter (m^2, m2), square-kilometer (km^2, km2), square-inch (in^2, in2), square-foot (ft^2, ft2), square-yard (y^2, y2), square-mile (mi^2, mi2), are (a), hectare (ha), acre (ac) | +| Information | bit, byte | +| Length | centimeter (cm), decimeter (dm), meter (m), kilometer (km), inch (in), foot (ft), yard (y), mile (mi), nautical-mile (nmi) | +| Temperature | Kelvin (K), Celsius (C), Fahrenheit (F) | +| Volume | cubic-centimeter (cm^3, cm3), cubic-decimeter (dm^3, dm3), liter (l), cubic-meter (m^3, m3), cubic-inch (in^3, in3), fluid-ounce (fl-oz), cubic-foot (ft^3, ft3), cubic-yard (y^3, y3) | +| Weight | gram (g), kilogram (kg), ton (t), ounce (oz), pound (lb) | +| Cooking (metric only, U.S. and imperial units differ slightly) | teaspoon (tsp), tablespoon (tbsp), cup | + +### Supported prefixes + +| Prefix | Power of 10 | +| ------ | ----------- | +| atto | 10-18 | +| pico | 10-15 | +| femto | 10-12 | +| nano | 10-9 | +| micro | 10-6 | +| milli | 10-3 | +| centi | 10-2 | +| deci | 10-1 | +| deca | 101 | +| hecto | 102 | +| kilo | 103 | +| mega | 106 | +| giga | 109 | +| tera | 1012 | +| peta | 1015 | +| exa | 1018 | + +### Usage examples + +| Message | Response | +| ------- | ------ | +| `@convert 12 celsius fahrenheit` | 12.0 celsius = 53.600054 fahrenheit | +| `@convert 0.002 kilomile millimeter` | 0.002 kilomile = 3218688.0 millimeter | +| `@convert 31.5 square-mile ha | 31.5 square-mile = 8158.4625 ha | +| `@convert 56 g lb` | 56.0 g = 0.12345887 lb | + +## Notes + +* You can use multiple `@convert` statements in a message, the response will look accordingly: +![multiple-converts](multiple-converts.png) + +* Enter `@convert help` to display a quick overview of the converter's functionality. + +* For bits and bytes, the prefixes change the figure differently: 1 kilobyte is 1024 bytes, +1 megabyte is 1048576 bytes, etc. diff --git a/contrib_bots/lib/ConverterBot/multiple-converts.png b/contrib_bots/lib/ConverterBot/multiple-converts.png new file mode 100644 index 0000000000000000000000000000000000000000..f198396e33bcee15060cbfa53435e959804c11e4 GIT binary patch literal 54989 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 HdfxvBVm*oQ literal 0 HcmV?d00001 diff --git a/contrib_bots/lib/converter.py b/contrib_bots/lib/converter.py new file mode 100644 index 0000000..eec2291 --- /dev/null +++ b/contrib_bots/lib/converter.py @@ -0,0 +1,275 @@ +# See readme.md for instructions on running this code. + +from __future__ import division +from past.utils import old_div + +import copy +from math import log10, floor + +# A dictionary allowing the conversion of each unit to its base unit. +# An entry consists of the unit's name, a constant number and a constant +# factor that need to be added and multiplied to convert the unit into +# the base unit in the last parameter. +UNITS = {'bit': [0, 1, 'bit'], + 'byte': [0, 8, 'bit'], + 'cubic-centimeter': [0, 0.000001, 'cubic-meter'], + 'cubic-decimeter': [0, 0.001, 'cubic-meter'], + 'liter': [0, 0.001, 'cubic-meter'], + 'cubic-meter': [0, 1, 'cubic-meter'], + 'cubic-inch': [0, 0.000016387064, 'cubic-meter'], + 'fluid-ounce': [0, 0.000029574, 'cubic-meter'], + 'cubic-foot': [0, 0.028316846592, 'cubic-meter'], + 'cubic-yard': [0, 0.764554857984, 'cubic-meter'], + 'teaspoon': [0, 0.0000049289216, 'cubic-meter'], + 'tablespoon': [0, 0.000014787, 'cubic-meter'], + 'cup': [0, 0.00023658823648491, 'cubic-meter'], + 'gram': [0, 1, 'gram'], + 'kilogram': [0, 1000, 'gram'], + 'ton': [0, 1000000, 'gram'], + 'ounce': [0, 28.349523125, 'gram'], + 'pound': [0, 453.59237, 'gram'], + 'kelvin': [0, 1, 'kelvin'], + 'celsius': [273.15, 1, 'kelvin'], + 'fahrenheit': [255.372222, 0.555555, 'kelvin'], + 'centimeter': [0, 0.01, 'meter'], + 'decimeter': [0, 0.1, 'meter'], + 'meter': [0, 1, 'meter'], + 'kilometer': [0, 1000, 'meter'], + 'inch': [0, 0.0254, 'meter'], + 'foot': [0, 0.3048, 'meter'], + 'yard': [0, 0.9144, 'meter'], + 'mile': [0, 1609.344, 'meter'], + 'nautical-mile': [0, 1852, 'meter'], + 'square-centimeter': [0, 0.0001, 'square-meter'], + 'square-decimeter': [0, 0.01, 'square-meter'], + 'square-meter': [0, 1, 'square-meter'], + 'square-kilometer': [0, 1000000, 'square-meter'], + 'square-inch': [0, 0.00064516, 'square-meter'], + 'square-foot': [0, 0.09290304, 'square-meter'], + 'square-yard': [0, 0.83612736, 'square-meter'], + 'square-mile': [0, 2589988.110336, 'square-meter'], + 'are': [0, 100, 'square-meter'], + 'hectare': [0, 10000, 'square-meter'], + 'acre': [0, 4046.8564224, 'square-meter']} + +PREFIXES = {'atto': -18, + 'femto': -15, + 'pico': -12, + 'nano': -9, + 'micro': -6, + 'milli': -3, + 'centi': -2, + 'deci': -1, + 'deca': 1, + 'hecto': 2, + 'kilo': 3, + 'mega': 6, + 'giga': 9, + 'tera': 12, + 'peta': 15, + 'exa': 18} + +ALIASES = {'a': 'are', + 'ac': 'acre', + 'c': 'celsius', + 'cm': 'centimeter', + 'cm2': 'square-centimeter', + 'cm3': 'cubic-centimeter', + 'cm^2': 'square-centimeter', + 'cm^3': 'cubic-centimeter', + 'dm': 'decimeter', + 'dm2': 'square-decimeter', + 'dm3': 'cubic-decimeter', + 'dm^2': 'square-decimeter', + 'dm^3': 'cubic-decimeter', + 'f': 'fahrenheit', + 'fl-oz': 'fluid-ounce', + 'ft': 'foot', + 'ft2': 'square-foot', + 'ft3': 'cubic-foot', + 'ft^2': 'square-foot', + 'ft^3': 'cubic-foot', + 'g': 'gram', + 'ha': 'hectare', + 'in': 'inch', + 'in2': 'square-inch', + 'in3': 'cubic-inch', + 'in^2': 'square-inch', + 'in^3': 'cubic-inch', + 'k': 'kelvin', + 'kg': 'kilogram', + 'km': 'kilometer', + 'km2': 'square-kilometer', + 'km^2': 'square-kilometer', + 'l': 'liter', + 'lb': 'pound', + 'm': 'meter', + 'm2': 'square-meter', + 'm3': 'cubic-meter', + 'm^2': 'square-meter', + 'm^3': 'cubic-meter', + 'mi': 'mile', + 'mi2': 'square-mile', + 'mi^2': 'square-mile', + 'nmi': 'nautical-mile', + 'oz': 'ounce', + 't': 'ton', + 'tbsp': 'tablespoon', + 'tsp': 'teaspoon', + 'y': 'yard', + 'y2': 'square-yard', + 'y3': 'cubic-yard', + 'y^2': 'square-yard', + 'y^3': 'cubic-yard'} + +HELP_MESSAGE = ('Converter usage:\n' + '`@convert `\n' + 'Converts `number` in the unit to ' + 'the and prints the result\n' + '`number`: integer or floating point number, e.g. 12, 13.05, 0.002\n' + ' and are two of the following units:\n' + '* square-centimeter (cm^2, cm2), square-decimeter (dm^2, dm2), ' + 'square-meter (m^2, m2), square-kilometer (km^2, km2),' + ' square-inch (in^2, in2), square-foot (ft^2, ft2), square-yard (y^2, y2), ' + ' square-mile(mi^2, mi2), are (a), hectare (ha), acre (ac)\n' + '* bit, byte\n' + '* centimeter (cm), decimeter(dm), meter (m),' + ' kilometer (km), inch (in), foot (ft), yard (y),' + ' mile (mi), nautical-mile (nmi)\n' + '* Kelvin (K), Celsius(C), Fahrenheit (F)\n' + '* cubic-centimeter (cm^3, cm3), cubic-decimeter (dm^3, dm3), liter (l), ' + 'cubic-meter (m^3, m3), cubic-inch (in^3, in3), fluid-ounce (fl-oz), ' + 'cubic-foot (ft^3, ft3), cubic-yard (y^3, y3)\n' + '* gram (g), kilogram (kg), ton (t), ounce (oz), pound(lb)\n' + '* (metric only, U.S. and imperial units differ slightly:) teaspoon (tsp), tablespoon (tbsp), cup\n\n\n' + 'Allowed prefixes are:\n' + '* atto, pico, femto, nano, micro, milli, centi, deci\n' + '* deca, hecto, kilo, mega, giga, tera, peta, exa\n\n\n' + 'Usage examples:\n' + '* `@convert 12 celsius fahrenheit`\n' + '* `@convert 0.002 kilomile millimeter`\n' + '* `@convert 31.5 square-mile ha`\n' + '* `@convert 56 g lb`\n') + +QUICK_HELP = 'Enter `@convert help` for help on using the converter.' + +def is_float(value): + try: + float(value) + return True + except ValueError: + return False + +# Rounds the number 'x' to 'digits' significant digits. +# A normal 'round()' would round the number to an absolute amount of +# fractional decimals, e.g. 0.00045 would become 0.0. +# 'round_to()' rounds only the digits that are not 0. +# 0.00045 would then become 0.0005. +def round_to(x, digits): + return round(x, digits-int(floor(log10(abs(x))))) + +class ConverterHandler(object): + ''' + This plugin allows users to make conversions between various units, + e.g. Celsius to Fahrenheit, or kilobytes to gigabytes. + It looks for messages of the format + '@convert ' + The message '@convert help' posts a short description of how to use + the plugin, along with a list of all supported units. + ''' + + def usage(self): + return ''' + This plugin allows users to make conversions between + various units, e.g. Celsius to Fahrenheit, + or kilobytes to gigabytes. It looks for messages of + the format '@convert ' + The message '@convert help' posts a short description of + how to use the plugin, along with a list of + all supported units. + ''' + + def triage_message(self, message, client): + return '@convert' in message['content'] + + def handle_message(self, message, client, state_handler): + content = message['content'] + + words = content.lower().split() + convert_indexes = [i for i, word in enumerate(words) if word == "@convert"] + results = [] + + for convert_index in convert_indexes: + if (convert_index + 1) < len(words) and words[convert_index + 1] == 'help': + results.append(HELP_MESSAGE) + continue + if (convert_index + 3) < len(words): + number = words[convert_index + 1] + unit_from = ALIASES.get(words[convert_index + 2], words[convert_index + 2]) + unit_to = ALIASES.get(words[convert_index + 3], words[convert_index + 3]) + exponent = 0 + + if not is_float(number): + results.append(number + ' is not a valid number. ' + QUICK_HELP) + continue + + number = float(number) + number_res = copy.copy(number) + + for key, exp in PREFIXES.items(): + if unit_from.startswith(key): + exponent += exp + unit_from = unit_from[len(key):] + if unit_to.startswith(key): + exponent -= exp + unit_to = unit_to[len(key):] + + uf_to_std = UNITS.get(unit_from, False) + ut_to_std = UNITS.get(unit_to, False) + + if uf_to_std is False: + results.append(unit_from + ' is not a valid unit. ' + QUICK_HELP) + if ut_to_std is False: + results.append(unit_to + ' is not a valid unit.' + QUICK_HELP) + if uf_to_std is False or ut_to_std is False: + continue + + base_unit = uf_to_std[2] + if uf_to_std[2] != ut_to_std[2]: + unit_from = unit_from.capitalize() if uf_to_std[2] == 'kelvin' else unit_from + results.append(unit_to.capitalize() + ' and ' + unit_from + + ' are not from the same category. ' + QUICK_HELP) + continue + + # perform the conversion between the units + number_res *= uf_to_std[1] + number_res += uf_to_std[0] + number_res -= ut_to_std[0] + number_res /= ut_to_std[1] + + if base_unit == 'bit': + number_res *= 1024 ** (old_div(exponent, float(3))) + else: + number_res *= 10 ** exponent + number_res = round_to(number_res, 7) + + results.append('{} {} = {} {}'.format(number, + words[convert_index + 2], + number_res, + words[convert_index + 3])) + + else: + results.append('Too few arguments given. ' + QUICK_HELP) + + new_content = '' + for idx, result in enumerate(results, 1): + new_content += ((str(idx) + '. conversion: ') if len(results) > 1 else '') + result + '\n' + + client.send_message(dict( + type='stream', + to=message['display_recipient'], + subject=message['subject'], + content=new_content, + )) + +handler_class = ConverterHandler