Dynamic place queries
-
A new placeDataProvider property on
EngineCustomization
supports natural language functions that include places that are dynamically resolved over the internet. -
Ensure the
dynamicPlaceQueries
flag is enabled onEngineFeatureFlags
to enable this feature (the default is off) -
Dynamic places are supported in natural language functions, for example:
- "time in Ubud, Bali"
- "distance between Bellingen & Nowra"
- "weather in Assisi, Perugia"
- "temperature in Narva, Estonia"
A PlaceDataProvider
implementation asynchronously geocodes a string query. You can optionally also enable distance calculations between by implementing another function.
protocol PlaceDataProvider {
/// Geocode a given string request
/// - For example, this might be a place like "Spoleto, Umbria, Italy"
/// - On Apple platforms, you can use Core Location's `CLGeocoder/geocodeAddressString` class for this
func placeDataFor(request: String) async throws -> PlaceData?
/// Calculate the distance between two GPS locations
/// On Apple platforms, you can use Core Location's `CLLocation/distance(from:)` function to calculate this
/// - This is a synchronous call, because network access is not required to calculate this
/// - Implement this function to enable "distance from (place) to (place)" style word functions
/// - Return a unit expression of length (miles or km, up to you)
func distanceBetween(location1: PlaceData.Coordinates, location2: PlaceData.Coordinates) -> UnitExpression?
}
Historical currency conversions
- The
CurrencyRateProvider
protocol offers a new function to fetch historical currency rates:
func fetchRateInBackgroundFor(request: CurrencyRateRequest) async -> Decimal?
- Get the conversion date from the request's new
date
property and dispatch a query to a web-based data source that supports historical currency conversions (like CurrencyLayer). - The synchronous variant
rateFor(request: CurrencyRateRequest) -> Decimal?
is polled first, to let you return a cached historical rate if available. - Ensure the
historicalCurrencyQueries
flag is enabled onEngineFeatureFlags
to enable this feature (the default is off)
Historical weather queries
WeatherDataRequest
now includes an optionaldatestamp
property.- Ensure the
historicalWeatherQueries
flag is enabled onEngineFeatureFlags
to enable this feature (the default is off)
Alternative Result Generator
- A new
AlternativeResultGenerator
class can intelligently convert a givenCalculationResult
into relevant alternative forms - For example, a decimal number might be converted into hex, binary and octal, or if below zero, into a fraction, and if above a certain threshold, into scientific notation
- A unit of time will be converted into a laptime (hh:mm:ss) and timespan (days, hours, minutes, seconds)
- A date will be converted into ISO8601 format, and a unix timestamp
Date Interval Parsing from String
- A new
dateIntervalFor(_ expression: String) -> DateInterval
onCalculator
offers intelligent date interval (start and end date) parsing that might be used to power a natural language event scheduling feature
Loading engine content from an external bundle
SoulverCore now supports loading its content files (containing places, units & functions, etc) from an externally located bundle directory. Previous versions always loaded resources included in the framework's resource folder.
To load resources from an external source:
- First make a resources bundle
ResourceBundle(url: URL)?
with a URL pointing to your resources bundle. - This initializer is failable to ensure that your resources bundle is valid
- Use the dedicated initializer on
EngineCustomization
that takes a ResourcesBundle:init(resourcesBundle: ResourceBundle, locale: Locale)
Breaking API changes
In connection with allowing an EngineCustomization to be loaded from an external bundle, we've moved away from all singletons in the framework, including CurrencyList
and StaticResources
.
- Functions for getting lists of content primitives (currencies & places) formally provided by these objects are now available on
EngineCustomization
Minor features
- Additional percentage shorthand: "5 of 50" (as a shorthand of "5 as a % of 50")
- Convert time to decimal: "10:45 to decimal" (= 10.75)
- Support for interpreting sub-zero numbers like
0.001
as0,001
in an EU locale (withMisplacedThousandsSeparatorBehavior
set tointerpretAsDecimalPoint
)
Bug fixes
- Fixed a crash when doing
fact(99999.999)
- Fixed a bug with auto converting a conversion in parentheses while using answer auto conversion mode
- Fixed a bug where you couldn't convert rates of fluid oz/acre into mL/ha (because the first rate was being converted into meters)