[feat] plugins: new unit converter plugin
This commit is contained in:
		
							parent
							
								
									b3b1258e4e
								
							
						
					
					
						commit
						46efb2f36d
					
				| @ -238,7 +238,10 @@ def unit_to_str(unit): | ||||
|     for prefix in WIKIDATA_PREFIX: | ||||
|         if unit.startswith(prefix): | ||||
|             wikidata_entity = unit[len(prefix) :] | ||||
|             return WIKIDATA_UNITS.get(wikidata_entity, unit) | ||||
|             real_unit = WIKIDATA_UNITS.get(wikidata_entity) | ||||
|             if real_unit is None: | ||||
|                 return unit | ||||
|             return real_unit['symbol'] | ||||
|     return unit | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										76
									
								
								searx/plugins/unit_converter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								searx/plugins/unit_converter.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| # SPDX-License-Identifier: AGPL-3.0-or-later | ||||
| """Calculate mathematical expressions using ack#eval | ||||
| """ | ||||
| 
 | ||||
| from flask_babel import gettext | ||||
| 
 | ||||
| from searx.data import WIKIDATA_UNITS | ||||
| 
 | ||||
| name = "Unit converter plugin" | ||||
| description = gettext("Convert between units") | ||||
| default_on = True | ||||
| 
 | ||||
| CONVERT_KEYWORDS = ["in", "to", "as"] | ||||
| 
 | ||||
| 
 | ||||
| def _convert(from_value, source_si_factor, target_si_factor): | ||||
|     return from_value * source_si_factor / target_si_factor | ||||
| 
 | ||||
| 
 | ||||
| def _parse_text_and_convert(search, splitted_query): | ||||
|     if len(splitted_query) != 2 or splitted_query[0].strip() == "" or splitted_query[1].strip() == "": | ||||
|         return | ||||
| 
 | ||||
|     from_value = "" | ||||
|     from_unit_key = "" | ||||
| 
 | ||||
|     # only parse digits as value that belong together | ||||
|     read_alpha = False | ||||
|     for c in splitted_query[0]: | ||||
|         if not read_alpha and (c in ("-", ".") or str.isdigit(c)): | ||||
|             from_value += c | ||||
|             read_alpha = True | ||||
|         elif c != " ": | ||||
|             from_unit_key += c | ||||
| 
 | ||||
|     to_unit_key = splitted_query[1].strip() | ||||
| 
 | ||||
|     from_unit = None | ||||
|     to_unit = None | ||||
| 
 | ||||
|     for unit in WIKIDATA_UNITS.values(): | ||||
|         if unit['symbol'] == from_unit_key: | ||||
|             from_unit = unit | ||||
| 
 | ||||
|         if unit['symbol'] == to_unit_key: | ||||
|             to_unit = unit | ||||
| 
 | ||||
|         if from_unit and to_unit: | ||||
|             break | ||||
| 
 | ||||
|     if from_unit is None or to_unit is None or to_unit.get('si_name') != from_unit.get('si_name'): | ||||
|         return | ||||
| 
 | ||||
|     result = _convert(float(from_value), from_unit['to_si_factor'], to_unit['to_si_factor']) | ||||
|     search.result_container.answers['conversion'] = {'answer': f"{result:g} {to_unit['symbol']}"} | ||||
| 
 | ||||
| 
 | ||||
| def post_search(_request, search): | ||||
|     # only convert between units on the first page | ||||
|     if search.search_query.pageno > 1: | ||||
|         return True | ||||
| 
 | ||||
|     query = search.search_query.query | ||||
|     query_parts = query.split(" ") | ||||
| 
 | ||||
|     if len(query_parts) < 3: | ||||
|         return True | ||||
| 
 | ||||
|     for query_part in query_parts: | ||||
|         for keyword in CONVERT_KEYWORDS: | ||||
|             if query_part == keyword: | ||||
|                 keyword_split = query.split(keyword, 1) | ||||
|                 _parse_text_and_convert(search, keyword_split) | ||||
|                 return True | ||||
| 
 | ||||
|     return True | ||||
| @ -29,31 +29,46 @@ set_loggers(wikidata, 'wikidata') | ||||
| # * https://www.wikidata.org/wiki/Help:Ranking | ||||
| # * https://www.mediawiki.org/wiki/Wikibase/Indexing/RDF_Dump_Format ("Statement representation" section) | ||||
| # * https://w.wiki/32BT | ||||
| # * https://en.wikibooks.org/wiki/SPARQL/WIKIDATA_Precision,_Units_and_Coordinates#Quantities | ||||
| #   see the result for https://www.wikidata.org/wiki/Q11582 | ||||
| #   there are multiple symbols the same rank | ||||
| SARQL_REQUEST = """ | ||||
| SELECT DISTINCT ?item ?symbol | ||||
| SELECT DISTINCT ?item ?symbol ?tosi ?tosiUnit | ||||
| WHERE | ||||
| { | ||||
|   ?item wdt:P31/wdt:P279 wd:Q47574 . | ||||
|   ?item p:P5061 ?symbolP . | ||||
|   ?symbolP ps:P5061 ?symbol ; | ||||
|            wikibase:rank ?rank . | ||||
|   OPTIONAL { | ||||
|     ?item p:P2370 ?tosistmt . | ||||
|     ?tosistmt psv:P2370 ?tosinode . | ||||
|     ?tosinode wikibase:quantityAmount ?tosi . | ||||
|     ?tosinode wikibase:quantityUnit ?tosiUnit . | ||||
|   } | ||||
|   FILTER(LANG(?symbol) = "en"). | ||||
| } | ||||
| ORDER BY ?item DESC(?rank) ?symbol | ||||
| """ | ||||
| 
 | ||||
| _wikidata_url = "https://www.wikidata.org/entity/" | ||||
| 
 | ||||
| 
 | ||||
| def get_data(): | ||||
|     results = collections.OrderedDict() | ||||
|     response = wikidata.send_wikidata_query(SARQL_REQUEST) | ||||
|     for unit in response['results']['bindings']: | ||||
|         name = unit['item']['value'].replace('http://www.wikidata.org/entity/', '') | ||||
|         unit = unit['symbol']['value'] | ||||
|         name = unit['item']['value'].replace(_wikidata_url, '') | ||||
|         symbol = unit['symbol']['value'] | ||||
|         si_name = unit.get('tosiUnit', {}).get('value', '').replace(_wikidata_url, '') | ||||
|         to_si_factor = unit.get('tosi', {}).get('value', '') | ||||
|         if name not in results: | ||||
|             # ignore duplicate: always use the first one | ||||
|             results[name] = unit | ||||
|             results[name] = { | ||||
|                 'symbol': symbol, | ||||
|                 'si_name': si_name if si_name else None, | ||||
|                 'to_si_factor': float(to_si_factor) if to_si_factor else None, | ||||
|             } | ||||
|     return results | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user