import random from copy import deepcopy from typing import Dict, List, Union from .long_context import ( CAR_STATUS_METADATA_EXTENSION, INTERMEDIARY_CITIES, LONG_WEATHER_EXTENSION, PARKING_BRAKE_INSTRUCTION, ) MAX_FUEL_LEVEL = 50 MIN_FUEL_LEVEL = 0.0 MILE_PER_GALLON = 20.0 MAX_BATTERY_VOLTAGE = 14.0 MIN_BATTERY_VOLTAGE = 10.0 DEFAULT_STATE = { "random_seed": 141053, "fuelLevel": 0.0, "batteryVoltage": 12.6, "engine_state": "stopped", "remainingUnlockedDoors": 4, "doorStatus": { "driver": "unlocked", "passenger": "unlocked", "rear_left": "unlocked", "rear_right": "unlocked", }, "acTemperature": 25.0, "fanSpeed": 50, "acMode": "auto", "humidityLevel": 50.0, "headLightStatus": "off", "parkingBrakeStatus": "released", "_parkingBrakeForce": 0.0, "_slopeAngle": 0.0, "brakePedalStatus": "released", "brakePedalForce": 0.0, "distanceToNextVehicle": 50.0, "cruiseStatus": "inactive", "destination": "None", "frontLeftTirePressure": 32.0, "frontRightTirePressure": 32.0, "rearLeftTirePressure": 30.0, "rearRightTirePressure": 30.0, } class VehicleControlAPI: def __init__(self): """ Initializes the vehicle control API with default values. """ self.fuelLevel: float self.batteryVoltage: float self.engine_state: str self.remainingUnlockedDoors: int self.doorStatus: Dict[str, str] self.acTemperature: float self.fanSpeed: int self.acMode: str self.humidityLevel: float self.headLightStatus: str self.parkingBrakeStatus: str self._parkingBrakeForce: float self._slopeAngle: float self.brakePedalStatus: str self._brakePedalForce: float self.distanceToNextVehicle: float self.cruiseStatus: str self.destination: str self.frontLeftTirePressure: float self.frontRightTirePressure: float self.rearLeftTirePressure: float self.rearRightTirePressure: float self._api_description = "This tool belongs to the vehicle control system, which allows users to control various aspects of the car such as engine, doors, climate control, lights, and more." def _load_scenario(self, scenario: dict, long_context=False) -> None: """ Loads the scenario for the vehicle control. Args: scenario (Dict): The scenario to load. """ DEFAULT_STATE_COPY = deepcopy(DEFAULT_STATE) self._random = random.Random( (scenario.get("random_seed", DEFAULT_STATE_COPY["random_seed"])) ) self.fuelLevel = scenario.get( "fuelLevel", DEFAULT_STATE_COPY["fuelLevel"] ) # in gallons self.batteryVoltage = scenario.get( "batteryVoltage", DEFAULT_STATE_COPY["batteryVoltage"] ) # in volts self.engine_state = scenario.get( "engineState", DEFAULT_STATE_COPY["engine_state"] ) # running, stopped self.remainingUnlockedDoors = scenario.get( "remainingUnlockedDoors", DEFAULT_STATE_COPY["remainingUnlockedDoors"] ) # driver, passenger, rear_left, rear_right self.doorStatus = scenario.get( "doorStatus", DEFAULT_STATE_COPY["doorStatus"], ) self.remainingUnlockedDoors = 4 - len( [1 for door in self.doorStatus.keys() if self.doorStatus[door] == "locked"] ) self.acTemperature = scenario.get( "acTemperature", DEFAULT_STATE_COPY["acTemperature"] ) # in degree Celsius self.fanSpeed = scenario.get("fanSpeed", DEFAULT_STATE_COPY["fanSpeed"]) # 0 to 100 self.acMode = scenario.get( "acMode", DEFAULT_STATE_COPY["acMode"] ) # auto, cool, heat, defrost self.humidityLevel = scenario.get( "humidityLevel", DEFAULT_STATE_COPY["humidityLevel"] ) # in percentage self.headLightStatus = scenario.get( "headLightStatus", DEFAULT_STATE_COPY["headLightStatus"] ) # on, off self.parkingBrakeStatus = scenario.get( "parkingBrakeStatus", DEFAULT_STATE_COPY["parkingBrakeStatus"] ) # released, engaged self._parkingBrakeForce = scenario.get( "parkingBrakeForce", DEFAULT_STATE_COPY["_parkingBrakeForce"] ) # in Newtons self._slopeAngle = scenario.get( "slopeAngle", DEFAULT_STATE_COPY["_slopeAngle"] ) # in degrees self.brakePedalStatus = scenario.get( "brakePedalStatus", DEFAULT_STATE_COPY["brakePedalStatus"] ) # pressed, released self._brakePedalForce = scenario.get( "brakePedalForce", DEFAULT_STATE_COPY["brakePedalForce"] ) # in Newtons self.distanceToNextVehicle = scenario.get( "distanceToNextVehicle", DEFAULT_STATE_COPY["distanceToNextVehicle"] ) # in meters self.cruiseStatus = scenario.get( "cruiseStatus", DEFAULT_STATE_COPY["cruiseStatus"] ) # active, inactive self.destination = scenario.get("destination", DEFAULT_STATE_COPY["destination"]) self.frontLeftTirePressure = scenario.get( "frontLeftTirePressure", DEFAULT_STATE_COPY["frontLeftTirePressure"] ) self.frontRightTirePressure = scenario.get( "frontRightTirePressure", DEFAULT_STATE_COPY["frontRightTirePressure"] ) self.rearLeftTirePressure = scenario.get( "rearLeftTirePressure", DEFAULT_STATE_COPY["rearLeftTirePressure"] ) self.rearRightTirePressure = scenario.get( "rearRightTirePressure", DEFAULT_STATE_COPY["rearRightTirePressure"] ) self.long_context = long_context def __eq__(self, value: object) -> bool: if not isinstance(value, VehicleControlAPI): return False for attr_name in vars(self): if attr_name.startswith("_"): continue model_attr = getattr(self, attr_name) ground_truth_attr = getattr(value, attr_name) if model_attr != ground_truth_attr: return False return True def startEngine(self, ignitionMode: str) -> Dict[str, Union[str, float]]: """ Starts the engine of the vehicle. Args: ignitionMode (str): The ignition mode of the vehicle. [Enum]: ["START", "STOP"] Returns: engineState (str): The state of the engine. [Enum]: ["running", "stopped"] fuelLevel (float): The fuel level of the vehicle in gallons. batteryVoltage (float): The battery voltage of the vehicle in volts. """ if ignitionMode == "STOP": self.engine_state = "stopped" if self.remainingUnlockedDoors > 0: return { "error": "All doors must be locked before starting the engine. Here are the unlocked doors: " + ", ".join( [ door for door, status in self.doorStatus.items() if status == "unlocked" ] ) } if self.brakePedalStatus != "pressed": return {"error": "Brake pedal needs to be pressed when starting the engine."} if self._brakePedalForce != 1000.0: return {"error": "Must press the brake fully before starting the engine."} if self.fuelLevel < MIN_FUEL_LEVEL: return {"error": "Fuel tank is empty."} if ignitionMode == "START": self.engine_state = "running" else: return {"error": "Invalid ignition mode."} return { "engineState": self.engine_state, "fuelLevel": self.fuelLevel, "batteryVoltage": self.batteryVoltage, } def fillFuelTank(self, fuelAmount: float) -> Dict[str, Union[str, float]]: """ Fills the fuel tank of the vehicle. The fuel tank can hold up to 50 gallons. Args: fuelAmount (float): The amount of fuel to fill in gallons; this is the additional fuel to add to the tank. Returns: fuelLevel (float): The fuel level of the vehicle in gallons. """ if fuelAmount < 0: return {"error": "Fuel amount cannot be negative."} if self.fuelLevel + fuelAmount > MAX_FUEL_LEVEL: return {"error": "Cannot fill gas above the tank capacity."} if self.fuelLevel + fuelAmount < MIN_FUEL_LEVEL: return {"error": "Fuel tank is empty. Min fuel level is 0 gallons."} self.fuelLevel += fuelAmount return {"fuelLevel": self.fuelLevel} def lockDoors(self, unlock: bool, door: list[str]) -> Dict[str, Union[str, int]]: """ Locks the doors of the vehicle. Args: unlock (bool): True if the doors are to be unlocked, False otherwise. door (List[str]): The list of doors to lock or unlock. [Enum]: ["driver", "passenger", "rear_left", "rear_right"] Returns: lockStatus (str): The status of the lock. [Enum]: ["locked", "unlocked"] remainingUnlockedDoors (int): The number of remaining unlocked doors. """ if unlock: for d in door: if self.doorStatus[d] == "unlocked": continue self.doorStatus[d] = "unlocked" self.remainingUnlockedDoors += 1 return { "lockStatus": "unlocked", "remainingUnlockedDoors": self.remainingUnlockedDoors, } else: for d in door: if self.doorStatus[d] == "locked": continue self.doorStatus[d] = "locked" self.remainingUnlockedDoors -= 1 return { "lockStatus": "locked", "remainingUnlockedDoors": self.remainingUnlockedDoors, } def adjustClimateControl( self, temperature: float, unit: str = "celsius", fanSpeed: int = 50, mode: str = "auto", ) -> Dict[str, Union[str, float]]: """ Adjusts the climate control of the vehicle. Args: temperature (float): The temperature to set in degree. Default to be celsius. unit (str): [Optional] The unit of temperature. [Enum]: ["celsius", "fahrenheit"] fanSpeed (int): [Optional] The fan speed to set from 0 to 100. Default is 50. mode (str): [Optional] The climate mode to set. [Enum]: ["auto", "cool", "heat", "defrost"] Returns: currentTemperature (float): The current temperature set in degree Celsius. climateMode (str): The current climate mode set. humidityLevel (float): The humidity level in percentage. """ if not (0 <= fanSpeed <= 100): return {"error": "Fan speed must be between 0 and 100."} self.acTemperature = temperature if unit == "fahrenheit": self.acTemperature = (temperature - 32) * 5 / 9 self.fanSpeed = fanSpeed self.acMode = mode return { "currentACTemperature": temperature, "climateMode": mode, "humidityLevel": self.humidityLevel, } def get_outside_temperature_from_google(self) -> Dict[str, float]: """ Gets the outside temperature. Returns: outsideTemperature (float): The outside temperature in degree Celsius. """ if self.long_context: LONG_WEATHER_EXTENSION["outsideTemperature"] = self._random.uniform(-10.0, 40.0) return LONG_WEATHER_EXTENSION return {"outsideTemperature": self._random.uniform(-10.0, 40.0)} def get_outside_temperature_from_weather_com(self) -> Dict[str, float]: """ Gets the outside temperature. Returns: outsideTemperature (float): The outside temperature in degree Celsius. """ return {"error": 404} def setHeadlights(self, mode: str) -> Dict[str, str]: """ Sets the headlights of the vehicle. Args: mode (str): The mode of the headlights. [Enum]: ["on", "off", "auto"] Returns: headlightStatus (str): The status of the headlights. [Enum]: ["on", "off"] """ if mode not in ["on", "off", "auto"]: return {"error": "Invalid headlight mode."} if mode == "on": self.headLightStatus = "on" return {"headlightStatus": "on"} else: self.headLightStatus = "off" return {"headlightStatus": "off"} def displayCarStatus(self, option: str) -> Dict[str, Union[str, float, Dict[str, str]]]: """ Displays the status of the vehicle based on the provided display option. Args: option (str): The option to display. [Enum]: ["fuel", "battery", "doors", "climate", "headlights", "parkingBrake", "brakePadle", "engine"] Returns: status (Dict): The status of the vehicle based on the option. - fuelLevel (float): [Optional] The fuel level of the vehicle in gallons. - batteryVoltage (float): [Optional] The battery voltage of the vehicle in volts. - doorStatus (Dict): [Optional] The status of the doors. - driver (str): The status of the driver door. [Enum]: ["locked", "unlocked"] - passenger (str): The status of the passenger door. [Enum]: ["locked", "unlocked"] - rear_left (str): The status of the rear left door. [Enum]: ["locked", "unlocked"] - rear_right (str): The status of the rear right door. [Enum]: ["locked", "unlocked"] - currentACTemperature (float): [Optional] The current temperature set in degree Celsius. - fanSpeed (int): [Optional] The fan speed set from 0 to 100. - climateMode (str): [Optional] The climate mode set. [Enum]: ["auto", "cool", "heat", "defrost"] - humidityLevel (float): [Optional] The humidity level in percentage. - headlightStatus (str): [Optional] The status of the headlights. [Enum]: ["on", "off"] - parkingBrakeStatus (str): [Optional] The status of the brake. [Enum]: ["engaged", "released"] - parkingBrakeForce (float): [Optional] The force applied to the brake in Newtons. - slopeAngle (float): [Optional] The slope angle in degrees. - brakePedalStatus (str): [Optional] The status of the brake pedal. [Enum]: ["pressed", "released"] - brakePedalForce (float): [Optional] The force applied to the brake pedal in Newtons. - engineState (str): [Optional] The state of the engine. [Enum]: ["running", "stopped"] - metadata (str): [Optional] The metadata of the car. """ status = {} if self.long_context: status["metadata"] = CAR_STATUS_METADATA_EXTENSION if option == "fuel": status["fuelLevel"] = self.fuelLevel elif option == "battery": status["batteryVoltage"] = self.batteryVoltage elif option == "doors": status["doorStatus"] = self.doorStatus elif option == "climate": status["currentACTemperature"] = self.acTemperature status["fanSpeed"] = self.fanSpeed status["climateMode"] = self.acMode status["humidityLevel"] = self.humidityLevel elif option == "headlights": status["headlightStatus"] = self.headLightStatus elif option == "parkingBrake": status["parkingBrakeStatus"] = self.parkingBrakeStatus status["parkingBrakeForce"] = self._parkingBrakeForce status["slopeAngle"] = self._slopeAngle elif option == "brakePedal": status["brakePedalStatus"] = self.brakePedalStatus status["brakePedalForce"] = self._brakePedalForce elif option == "engine": status["engineState"] = self.engine_state else: status["error"] = "Invalid option" return status def activateParkingBrake(self, mode: str) -> Dict[str, Union[str, float]]: """ Activates the parking brake of the vehicle. Args: mode (str): The mode to set. [Enum]: ["engage", "release"] Returns: parkingBrakeStatus (str): The status of the brake. [Enum]: ["engaged", "released"] _parkingBrakeForce (float): The force applied to the brake in Newtons. _slopeAngle (float): The slope angle in degrees. """ if mode not in ["engage", "release"]: return {"error": "Invalid mode"} if mode == "engage": self.parkingBrakeStatus = "engaged" self._parkingBrakeForce = 500.0 self._slopeAngle = 10.0 if self.long_context: return { "parkingBrakeInstruction": PARKING_BRAKE_INSTRUCTION, "parkingBrakeStatus": "engaged", "_parkingBrakeForce": 500.0, "_slopeAngle": 10.0, } return {"parkingBrakeStatus": "engaged", "_parkingBrakeForce": 500.0, "_slopeAngle": 10.0} else: self.parkingBrakeStatus = "released" self._parkingBrakeForce = 0.0 self._slopeAngle = 10.0 if self.long_context: return { "parkingBrakeInstruction": PARKING_BRAKE_INSTRUCTION, "parkingBrakeStatus": "released", "_parkingBrakeForce": 0.0, "_slopeAngle": 10.0, } return {"parkingBrakeStatus": "released", "_parkingBrakeForce": 0.0, "_slopeAngle": 10.0} def pressBrakePedal(self, pedalPosition: float) -> Dict[str, Union[str, float]]: """ Presses the brake pedal based on pedal position. The brake pedal will be kept pressed until released. Args: pedalPosition (float): Position of the brake pedal, between 0 (not pressed) and 1 (fully pressed). Returns: brakePedalStatus (str): The status of the brake pedal. [Enum]: ["pressed", "released"] brakePedalForce (float): The force applied to the brake pedal in Newtons. """ # Validate pedal position is within 0 to 1 if not (0 <= pedalPosition <= 1): return {"error": "Pedal position must be between 0 and 1."} # Release the brake if pedal position is zero if pedalPosition == 0: self.brakePedalStatus = "released" self._brakePedalForce = 0.0 return {"brakePedalStatus": "released", "brakePedalForce": 0.0} # Calculate force based on pedal position max_brake_force = 1000 # Max force in Newtons force = pedalPosition * max_brake_force # Update the brake pedal status and force self.brakePedalStatus = "pressed" self._brakePedalForce = force return {"brakePedalStatus": "pressed", "brakePedalForce": float(force)} def releaseBrakePedal(self) -> Dict[str, Union[str, float]]: """ Releases the brake pedal of the vehicle. Returns: brakePedalStatus (str): The status of the brake pedal. [Enum]: ["pressed", "released"] brakePedalForce (float): The force applied to the brake pedal in Newtons. """ self.brakePedalStatus = "released" self._brakePedalForce = 0.0 return {"brakePedalStatus": "released", "brakePedalForce": 0.0} def setCruiseControl( self, speed: float, activate: bool, distanceToNextVehicle: float ) -> Dict[str, Union[str, float]]: """ Sets the cruise control of the vehicle. Args: speed (float): The speed to set in m/h. The speed should be between 0 and 120 and a multiple of 5. activate (bool): True to activate the cruise control, False to deactivate. distanceToNextVehicle (float): The distance to the next vehicle in meters. Returns: cruiseStatus (str): The status of the cruise control. [Enum]: ["active", "inactive"] currentSpeed (float): The current speed of the vehicle in km/h. distanceToNextVehicle (float): The distance to the next vehicle in meters. """ if self.engine_state == "stopped": return {"error": "Start the engine before activating the cruise control."} if activate: self.distanceToNextVehicle = distanceToNextVehicle if speed < 0 or speed > 120 or speed % 5 != 0: return {"error": "Invalid speed"} self.cruiseStatus = "active" return { "cruiseStatus": "active", "currentSpeed": speed, "distanceToNextVehicle": distanceToNextVehicle, } else: self.cruiseStatus = "inactive" self.distanceToNextVehicle = distanceToNextVehicle return { "cruiseStatus": "inactive", "currentSpeed": speed, "distanceToNextVehicle": distanceToNextVehicle, } def get_current_speed(self) -> Dict[str, float]: """ Gets the current speed of the vehicle. Returns: currentSpeed (float): The current speed of the vehicle in km/h. """ return {"currentSpeed": self._random.uniform(0.0, 120.0)} def display_log(self, messages: List[str]): """ Displays the log messages. Args: messages (List[str]): The list of messages to display. Returns: log (List[str]): The list of messages displayed. """ return {"log": messages} def estimate_drive_feasibility_by_mileage(self, distance: float) -> Dict[str, bool]: """ Estimates the milage of the vehicle given the distance needed to drive. Args: distance (float): The distance to travel in miles. Returns: canDrive (bool): True if the vehicle can drive the distance, False otherwise. """ if self.fuelLevel * MILE_PER_GALLON < distance: return {"canDrive": False} else: return {"canDrive": True} def liter_to_gallon(self, liter: float) -> Dict[str, float]: """ Converts the liter to gallon. Args: liter (float): The amount of liter to convert. Returns: gallon (float): The amount of gallon converted. """ return {"gallon": liter * 0.264172} def gallon_to_liter(self, gallon: float) -> Dict[str, float]: """ Converts the gallon to liter. Args: gallon (float): The amount of gallon to convert. Returns: liter (float): The amount of liter converted. """ return {"liter": gallon * 3.78541} def estimate_distance(self, cityA: str, cityB: str) -> Dict[str, float]: """ Estimates the distance between two cities. Args: cityA (str): The zipcode of the first city. cityB (str): The zipcode of the second city. Returns: distance (float): The distance between the two cities in km. intermediaryCities (List[str]): [Optional] The list of intermediary cities between the two cities. """ if (cityA == "83214" and cityB == "74532") or ( cityA == "74532" and cityB == "83214" ): distance = {"distance": 750.0} elif (cityA == "56108" and cityB == "62947") or ( cityA == "62947" and cityB == "56108" ): distance = {"distance": 320.0} elif (cityA == "71354" and cityB == "83462") or ( cityA == "83462" and cityB == "71354" ): distance = {"distance": 450.0} elif (cityA == "47329" and cityB == "52013") or ( cityA == "52013" and cityB == "47329" ): distance = {"distance": 290.0} elif (cityA == "69238" and cityB == "51479") or ( cityA == "51479" and cityB == "69238" ): distance = {"distance": 630.0} elif (cityA == "94016" and cityB == "83214") or ( cityA == "83214" and cityB == "94016" ): distance = {"distance": 980.0} elif (cityA == "94016" and cityB == "94704") or ( cityA == "94704" and cityB == "94016" ): distance = {"distance": 600.0} elif (cityA == "94704" and cityB == "08540") or ( cityA == "08540" and cityB == "94704" ): distance = {"distance": 2550.0} elif (cityA == "94016" and cityB == "08540") or ( cityA == "08540" and cityB == "94016" ): distance = {"distance": 1950.0} elif (cityA == "62947" and cityB == "47329") or ( cityA == "47329" and cityB == "62947" ): distance = {"distance": 1053.0} elif (cityA == "94016" and cityB == "62947") or ( cityA == "62947" and cityB == "94016" ): distance = {"distance": 780.0} elif (cityA == "74532" and cityB == "94016") or ( cityA == "94016" and cityB == "74532" ): distance = {"distance": 880.0} else: distance = {"error": "distance not found in database."} if self.long_context: distance["intermediaryCities"] = INTERMEDIARY_CITIES return distance def get_zipcode_based_on_city(self, city: str) -> Dict[str, str]: """ Gets the zipcode based on the city. Args: city (str): The name of the city. Returns: zipcode (str): The zipcode of the city. """ if city == "Rivermist": return {"zipcode": "83214"} elif city == "Stonebrook": return {"zipcode": "74532"} elif city == "Maplecrest": return {"zipcode": "56108"} elif city == "Silverpine": return {"zipcode": "62947"} elif city == "Shadowridge": return {"zipcode": "71354"} elif city == "Sunset Valley": return {"zipcode": "83462"} elif city == "Oakendale": return {"zipcode": "47329"} elif city == "Willowbend": return {"zipcode": "52013"} elif city == "Crescent Hollow": return {"zipcode": "69238"} elif city == "Autumnville": return {"zipcode": "51479"} elif city == "San Francisco": return {"zipcode": "94016"} else: return {"zipcode": "00000"} def set_navigation(self, destination: str) -> Dict[str, str]: """ Navigates to the destination. Args: destination (str): The destination to navigate in the format of street, city, state. Returns: status (str): The status of the navigation. """ self.destination = destination return {"status": "Navigating to " + destination} def check_tire_pressure(self): """ Checks the tire pressure of the vehicle. Returns: tirePressure (Dict): The tire pressure of the vehicle. - frontLeftTirePressure (float): The pressure of the front left tire in psi. - frontRightTirePressure (float): The pressure of the front right tire in psi. - rearLeftTirePressure (float): The pressure of the rear left tire in psi. - rearRightTirePressure (float): The pressure of the rear right tire in psi. - healthy_tire_pressure (bool): True if the tire pressure is healthy, False otherwise. - car_info (Dict): The metadata of the car. """ # This is the healthy standard the vehicle use, though the user might have different preferences healthy_tire_pressure = ( 30 <= ( self.frontLeftTirePressure + self.frontRightTirePressure + self.rearLeftTirePressure + self.rearRightTirePressure ) / 4 <= 35 ) tire_status = { "frontLeftTirePressure": self.frontLeftTirePressure, "frontRightTirePressure": self.frontRightTirePressure, "rearLeftTirePressure": self.rearLeftTirePressure, "rearRightTirePressure": self.rearRightTirePressure, "healthy_tire_pressure": healthy_tire_pressure, "car_info": {}, } if self.long_context: tire_status["car_info"] = CAR_STATUS_METADATA_EXTENSION return tire_status def find_nearest_tire_shop(self) -> Dict[str, str]: """ Finds the nearest tire shop. Returns: shopLocation (str): The location of the nearest tire shop. """ return {"shopLocation": "456 Oakwood Avenue, Rivermist, 83214"}