mirror of
https://github.com/yacy/yacy_search_server.git
synced 2026-03-11 16:22:26 -04:00
201 lines
8.0 KiB
Java
201 lines
8.0 KiB
Java
/**
|
|
* UnitConverterTool
|
|
* Copyright 2026 by Michael Peter Christen
|
|
* First released 06.02.2026 at https://yacy.net
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program in the file lgpl21.txt
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.yacy.ai.tools;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
|
|
import org.json.JSONArray;
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import net.yacy.ai.ToolHandler;
|
|
|
|
public class UnitConverterTool implements ToolHandler {
|
|
|
|
private static final String NAME = "unit_converter";
|
|
|
|
private static final Map<String, Double> LENGTH_TO_M = new HashMap<>();
|
|
private static final Map<String, Double> MASS_TO_KG = new HashMap<>();
|
|
private static final Map<String, Double> VOLUME_TO_L = new HashMap<>();
|
|
private static final Map<String, Double> SPEED_TO_MPS = new HashMap<>();
|
|
|
|
static {
|
|
LENGTH_TO_M.put("mm", 0.001d);
|
|
LENGTH_TO_M.put("cm", 0.01d);
|
|
LENGTH_TO_M.put("m", 1d);
|
|
LENGTH_TO_M.put("km", 1000d);
|
|
LENGTH_TO_M.put("in", 0.0254d);
|
|
LENGTH_TO_M.put("ft", 0.3048d);
|
|
LENGTH_TO_M.put("yd", 0.9144d);
|
|
LENGTH_TO_M.put("mi", 1609.344d);
|
|
|
|
MASS_TO_KG.put("mg", 0.000001d);
|
|
MASS_TO_KG.put("g", 0.001d);
|
|
MASS_TO_KG.put("kg", 1d);
|
|
MASS_TO_KG.put("t", 1000d);
|
|
MASS_TO_KG.put("oz", 0.028349523125d);
|
|
MASS_TO_KG.put("lb", 0.45359237d);
|
|
|
|
VOLUME_TO_L.put("ml", 0.001d);
|
|
VOLUME_TO_L.put("l", 1d);
|
|
VOLUME_TO_L.put("m3", 1000d);
|
|
VOLUME_TO_L.put("tsp", 0.00492892159375d);
|
|
VOLUME_TO_L.put("tbsp", 0.01478676478125d);
|
|
VOLUME_TO_L.put("cup", 0.2365882365d);
|
|
VOLUME_TO_L.put("pt", 0.473176473d);
|
|
VOLUME_TO_L.put("qt", 0.946352946d);
|
|
VOLUME_TO_L.put("gal", 3.785411784d);
|
|
|
|
SPEED_TO_MPS.put("m/s", 1d);
|
|
SPEED_TO_MPS.put("km/h", 0.2777777777777778d);
|
|
SPEED_TO_MPS.put("mph", 0.44704d);
|
|
SPEED_TO_MPS.put("kn", 0.514444d);
|
|
}
|
|
|
|
@Override
|
|
public JSONObject definition() throws JSONException {
|
|
JSONObject tool = new JSONObject(true);
|
|
tool.put("type", "function");
|
|
JSONObject fn = new JSONObject(true);
|
|
fn.put("name", NAME);
|
|
fn.put("description", "Convert numeric values between common units (length, mass, temperature, volume, speed).");
|
|
JSONObject params = new JSONObject(true);
|
|
params.put("type", "object");
|
|
JSONObject props = new JSONObject(true);
|
|
props.put("value", new JSONObject(true).put("type", "number").put("description", "Numeric input value."));
|
|
props.put("from", new JSONObject(true).put("type", "string").put("description", "Source unit, e.g. km, lb, C."));
|
|
props.put("to", new JSONObject(true).put("type", "string").put("description", "Target unit, e.g. mi, kg, F."));
|
|
params.put("properties", props);
|
|
params.put("required", new JSONArray().put("value").put("from").put("to"));
|
|
fn.put("parameters", params);
|
|
tool.put("function", fn);
|
|
return tool;
|
|
}
|
|
|
|
|
|
public int maxCallsPerTurn() {
|
|
return 10;
|
|
}
|
|
|
|
|
|
public String execute(String arguments) {
|
|
final JSONObject args;
|
|
try {
|
|
args = (arguments == null || arguments.isEmpty()) ? new JSONObject(true) : new JSONObject(arguments);
|
|
} catch (JSONException e) {
|
|
return ToolHandler.errorJson("Invalid arguments JSON");
|
|
}
|
|
if (!args.has("value")) return ToolHandler.errorJson("Missing value");
|
|
double value = args.optDouble("value", Double.NaN);
|
|
if (Double.isNaN(value) || Double.isInfinite(value)) return ToolHandler.errorJson("Invalid value");
|
|
String from = normalize(args.optString("from", ""));
|
|
String to = normalize(args.optString("to", ""));
|
|
if (from.isEmpty() || to.isEmpty()) return ToolHandler.errorJson("Missing from/to");
|
|
|
|
try {
|
|
ConversionResult result = convert(value, from, to);
|
|
JSONObject out = new JSONObject(true);
|
|
out.put("tool", NAME);
|
|
out.put("category", result.category);
|
|
out.put("value", value);
|
|
out.put("from", from);
|
|
out.put("to", to);
|
|
out.put("result", result.value);
|
|
return out.toString();
|
|
} catch (IllegalArgumentException | JSONException e) {
|
|
return ToolHandler.errorJson(e.getMessage());
|
|
}
|
|
}
|
|
|
|
private static ConversionResult convert(double value, String from, String to) {
|
|
if (isTemp(from) && isTemp(to)) {
|
|
double c = toCelsius(value, from);
|
|
return new ConversionResult("temperature", fromCelsius(c, to));
|
|
}
|
|
if (LENGTH_TO_M.containsKey(from) && LENGTH_TO_M.containsKey(to)) {
|
|
double m = value * LENGTH_TO_M.get(from);
|
|
return new ConversionResult("length", m / LENGTH_TO_M.get(to));
|
|
}
|
|
if (MASS_TO_KG.containsKey(from) && MASS_TO_KG.containsKey(to)) {
|
|
double kg = value * MASS_TO_KG.get(from);
|
|
return new ConversionResult("mass", kg / MASS_TO_KG.get(to));
|
|
}
|
|
if (VOLUME_TO_L.containsKey(from) && VOLUME_TO_L.containsKey(to)) {
|
|
double l = value * VOLUME_TO_L.get(from);
|
|
return new ConversionResult("volume", l / VOLUME_TO_L.get(to));
|
|
}
|
|
if (SPEED_TO_MPS.containsKey(from) && SPEED_TO_MPS.containsKey(to)) {
|
|
double mps = value * SPEED_TO_MPS.get(from);
|
|
return new ConversionResult("speed", mps / SPEED_TO_MPS.get(to));
|
|
}
|
|
throw new IllegalArgumentException("Unsupported conversion pair: " + from + " -> " + to);
|
|
}
|
|
|
|
private static boolean isTemp(String unit) {
|
|
return "c".equals(unit) || "f".equals(unit) || "k".equals(unit);
|
|
}
|
|
|
|
private static double toCelsius(double v, String from) {
|
|
if ("c".equals(from)) return v;
|
|
if ("f".equals(from)) return (v - 32d) * 5d / 9d;
|
|
if ("k".equals(from)) return v - 273.15d;
|
|
throw new IllegalArgumentException("Unsupported temperature unit: " + from);
|
|
}
|
|
|
|
private static double fromCelsius(double c, String to) {
|
|
if ("c".equals(to)) return c;
|
|
if ("f".equals(to)) return (c * 9d / 5d) + 32d;
|
|
if ("k".equals(to)) return c + 273.15d;
|
|
throw new IllegalArgumentException("Unsupported temperature unit: " + to);
|
|
}
|
|
|
|
private static String normalize(String s) {
|
|
if (s == null) return "";
|
|
String t = s.trim().toLowerCase(Locale.ROOT);
|
|
if ("°c".equals(t) || "celsius".equals(t)) return "c";
|
|
if ("°f".equals(t) || "fahrenheit".equals(t)) return "f";
|
|
if ("kelvin".equals(t)) return "k";
|
|
if ("meter".equals(t) || "metre".equals(t)) return "m";
|
|
if ("kilometer".equals(t) || "kilometre".equals(t)) return "km";
|
|
if ("mile".equals(t)) return "mi";
|
|
if ("foot".equals(t)) return "ft";
|
|
if ("inch".equals(t)) return "in";
|
|
if ("pound".equals(t)) return "lb";
|
|
if ("ounce".equals(t)) return "oz";
|
|
if ("liter".equals(t) || "litre".equals(t)) return "l";
|
|
if ("gallon".equals(t)) return "gal";
|
|
if ("kph".equals(t)) return "km/h";
|
|
if ("fps".equals(t)) return "ft/s";
|
|
return t;
|
|
}
|
|
|
|
private static final class ConversionResult {
|
|
final String category;
|
|
final double value;
|
|
ConversionResult(String category, double value) {
|
|
this.category = category;
|
|
this.value = value;
|
|
}
|
|
}
|
|
}
|