my eye

Add unit conversion

Committed 6465ad

--- a/pyproject.toml
+++ b/pyproject.toml

 nltk = "^3.8.1"
 restrictedpython = "^6.2"
 webint-owner = "^0.0"
+pint = "^0.22"
 
 [tool.poetry.group.dev.dependencies]
 bgq = {path="../bgq", develop=true}

--- a/webint_search/__init__.py
+++ b/webint_search/__init__.py

 import easyuri
 import eng_to_ipa
 import nltk
+import pint
 import pronouncing
 import requests
 import typesense
         "connection_timeout_seconds": 2,
     }
 )
+ureg = pint.UnitRegistry()
 books_schema = {
     "name": "books",
     "fields": [
             return app.view.index()
         query = form.q
 
+        conversion = None
+        units = {
+            # length
+            "fm": ("femtometer", "femtometer", "femtometers"),
+            "pm": ("picometer", "picometer", "picometers"),
+            "nm": ("nanometer", "nanometer", "nanometers"),
+            "μm": ("micron", "micron", "microns"),
+            "mm": ("millimeter", "millimeter", "millimeters"),
+            "cm": ("centimeter", "centimeter", "centimeters"),
+            "dm": ("decimeter", "decimeter", "decimeters"),
+            "m": ("meter", "meter", "meters"),
+            "dam": ("decameter", "decameter", "decameters"),
+            "hm": ("hectometer", "hectometer", "hectometers"),
+            "km": ("kilometer", "kilometer", "kilometers"),
+            "au": ("astronomical unit", "astronomical unit", "astronomical units"),
+            "ly": ("light year", "light year", "light years"),
+            "pc": ("parsec", "parsec", "parsecs"),
+            "mil": ("mil", "mil", "mils"),
+            "in": ("inch", "inch", "inches"),
+            "ft": ("foot", "foot", "feet"),
+            "yd": ("yard", "yard", "yards"),
+            "mi": ("mile", "mile", "miles"),
+            # temperature
+            "f": ("fahrenheit", "°F"),
+            "c": ("celsius", "°C"),
+            "k": ("kelvin", "°K"),
+            # area
+            r"sq\ in": ("square inch", "square inch", "square inches"),
+            r"sq\ ft": ("square foot", "square foot", "square feet"),
+            r"sq\ yd": ("square yard", "square yard", "square yards"),
+            r"sq\ mi": ("square mile", "square mile", "square miles"),
+            "acre": ("acre", "acre", "acres"),
+            "hectare": ("hectare", "hectare", "hectares"),
+            # volume
+            r"cu\ in": ("cubic inch", "cubic inch", "cubic inches"),
+            r"cu\ ft": ("cubic foot", "cubic foot", "cubic feet"),
+            r"cu\ yd": ("cubic yard", "cubic yard", "cubic yards"),
+            r"cu\ cm": ("cubic centimeter", "cubic centimeter", "cubic centimeter"),
+            "μl": ("microliter", "microliter", "microliters"),
+            "l": ("liter", "liter", "liters"),
+            "gal": ("gallon", "gallon", "gallons"),
+            "qt": ("quart", "quart", "quarts"),
+            "pt": ("pint", "pint", "pints"),
+            "cup": ("cup", "cup", "cups"),
+            "fl oz": ("fluid ounce", "fluid ounce", "fluid ounces"),
+            "tbls": ("tablespoon", "tablespoon", "tablespoons"),
+            "tspn": ("teaspoon", "teaspoon", "teaspoons"),
+            # weight
+            "μg": ("microgram", "microgram", "micrograms"),
+            "mg": ("milligram", "milligram", "millagrams"),
+            "g": ("gram", "gram", "grams"),
+            "kg": ("kilogram", "kilogram", "kilograms"),
+            "ct": ("carat", "carat", "carats"),
+            "oz": ("ounce", "ounce", "ounces"),
+            "lb": ("pound", "pound", "pounds"),
+            "tn": ("short ton", "short ton", "short tons"),
+            "t": ("metric ton", "metric ton", "metric tons"),
+            "lt": ("long ton", "long ton", "long tons"),
+            # time
+            "as": ("attosecond", "attosecond", "attoseconds"),
+            "fs": ("femtosecond", "femtosecond", "femtoseconds"),
+            "ps": ("picosecond", "picosecond", "picoseconds"),
+            "ns": ("nanosecond", "nanosecond", "nanoseconds"),
+            "sh": ("shake", "shake", "shakes"),
+            "μs": ("microsecond", "microsecond", "microseconds"),
+            "ms": ("millisecond", "millisecond", "milliseconds"),
+            "s": ("second", "second", "seconds"),
+            "min": ("minute", "minute", "minutes"),
+            "h": ("hour", "hour", "hours"),
+            "d": ("day", "day", "days"),
+            "wk": ("week", "week", "weeks"),
+            "fn": ("fortnight", "fortnight", "fortnights"),
+            "mo": ("month", "month", "months"),
+            "yr": ("year", "year", "years"),
+            "dec": ("decade", "decade", "decades"),
+            "cen": ("century", "century", "centuries"),
+            "ml": ("millennium", "millennium", "millennia"),
+            # data
+            "bit": ("bit", "bit", "bits"),
+            "kb": ("kilobit", "kilobit", "kilobits"),
+            "Mb": ("megabit", "megabit", "megabits"),
+            "Gb": ("gigabit", "gigabit", "gigabits"),
+            "Tb": ("terabit", "terabit", "terabits"),
+            "Pb": ("petabit", "petabit", "petabit"),
+            "Eb": ("exabit", "exabit", "exabit"),
+            "byte": ("byte", "bytes", "bytes"),
+            "kB": ("kilobyte", "kilobyte", "kilobytes"),
+            "MB": ("megabyte", "megabyte", "megabytes"),
+            "GB": ("gigabyte", "gigabyte", "gigabytes"),
+            "TB": ("terabyte", "terabyte", "terabytes"),
+            "PB": ("petabyte", "petabyte", "petabytes"),
+            "EB": ("exabyte", "exabyte", "exabytes"),
+            # speed
+            "kph": ("kilometer per hour", "kilometer/hour", "kilometers/hour"),
+            "kps": ("kilometer per second", "kilometer/second", "kilometers/second"),
+            "mph": ("mile per hour", "mile/hour", "miles/hour"),
+        }
+        if match := re.match(
+            rf"""^(?P<quantity>[\d.]+)(?P<from>({'|'.join(units)}))
+                 \ to\ (?P<to>({'|'.join(units)}))$""",
+            query,
+            re.VERBOSE,
+        ):
+            matches = match.groupdict()
+            from_quantity = float(matches["quantity"])
+            from_sig = len(matches["quantity"].partition(".")[2])
+            from_unit = units[matches["from"].replace(" ", r"\ ")]
+            to_unit = units[matches["to"].replace(" ", r"\ ")]
+            to_quantity = ureg.convert(
+                float(from_quantity),
+                getattr(ureg, from_unit[0].replace(" ", "_")),
+                getattr(ureg, to_unit[0].replace(" ", "_")),
+            )
+            output_from_unit = from_unit[1]
+            if len(from_unit) == 3 and from_quantity != 1:
+                output_from_unit = from_unit[2]
+            output_to_unit = to_unit[1]
+            if len(to_unit) == 3 and to_quantity != 1:
+                output_to_unit = to_unit[2]
+            conversion = (
+                f"{round(from_quantity, from_sig):n} {output_from_unit}",
+                f"{round(to_quantity, from_sig):n} {output_to_unit}",
+            )
+
         iw_profile = iw_lookup(query)
         ap_profile = ap_lookup(query)
 
         return app.view.results(
             query,
             # scope,
+            conversion,
             iw_profile,
             ap_profile,
             formatted_query,

--- a/webint_search/templates/results.html
+++ b/webint_search/templates/results.html

-$def with (query, iw_profile, ap_profile, formatted_query, result, ipa_pronunciation, cmu_pronunciation, definition, rhymes, web_results, code_projects, code_files, books)
+$def with (query, conversion, iw_profile, ap_profile, formatted_query, result, ipa_pronunciation, cmu_pronunciation, definition, rhymes, web_results, code_projects, code_files, books)
 $var breadcrumbs = ("search", "Search")
 
 <style>
     <pre>$pformat(profile)</pre>
     </details>
 
+$if conversion:
+    <p>$conversion[0] = $conversion[1]</p>
+
 $if result:
     <pre>$formatted_query<br>
     <big>$result</big></pre>