using System.Text.Json; namespace AIStudio.Provider; /// /// Parses the provider-specific JSON fragment stored in . /// /// /// The provider settings UI stores only the body of a JSON object, such as /// "temperature": 0.5. This parser wraps that fragment in curly braces, /// parses it as JSON, and converts it to regular CLR dictionaries, lists, and /// primitive values so request builders and feature detectors can inspect it. /// public static class AdditionalApiParametersParser { /// /// Try to parse an additional-API-parameters JSON fragment into a dictionary. /// /// The JSON object body without the surrounding curly braces. /// The parsed parameters if parsing succeeds; otherwise an empty dictionary. /// The JSON parsing error message if parsing fails; otherwise . /// if the fragment is empty or valid JSON; otherwise . public static bool TryParse(string additionalJsonApiParameters, out IDictionary parameters, out string? errorMessage) { parameters = new Dictionary(); errorMessage = null; if (string.IsNullOrWhiteSpace(additionalJsonApiParameters)) return true; try { // The UI stores only the object body, so wrap it before parsing. using var jsonDoc = JsonDocument.Parse($"{{{additionalJsonApiParameters}}}"); parameters = ConvertToDictionary(jsonDoc.RootElement); return true; } catch (JsonException ex) { errorMessage = ex.Message; return false; } } /// /// Remove keys from a parsed parameter dictionary using case-insensitive matching. /// /// The parsed parameter dictionary to mutate. /// The parameter names that should be removed. /// The same dictionary instance after the matching keys were removed. public static IDictionary RemoveKeys(IDictionary parameters, IEnumerable keysToRemove) { var removeSet = new HashSet(keysToRemove, StringComparer.OrdinalIgnoreCase); if (removeSet.Count is 0) return parameters; foreach (var key in parameters.Keys.ToList()) if (removeSet.Contains(key)) parameters.Remove(key); return parameters; } /// /// Convert a JSON object element into a dictionary of recursively converted CLR values. /// /// The JSON object element to convert. /// A dictionary containing all JSON object properties. private static IDictionary ConvertToDictionary(JsonElement element) { return element.EnumerateObject() .ToDictionary( p => p.Name, p => ConvertJsonValue(p.Value) ?? string.Empty ); } /// /// Convert a JSON value to the closest CLR representation used by provider request objects. /// /// The JSON element to convert. /// A string, number, boolean, dictionary, list, or empty string for unsupported/null values. private static object? ConvertJsonValue(JsonElement element) => element.ValueKind switch { JsonValueKind.String => element.GetString(), JsonValueKind.Number => element.TryGetInt32(out var i) ? i : element.TryGetInt64(out var l) ? l : element.TryGetDouble(out var d) ? d : element.GetDecimal(), JsonValueKind.True or JsonValueKind.False => element.GetBoolean(), JsonValueKind.Null => string.Empty, JsonValueKind.Object => ConvertToDictionary(element), JsonValueKind.Array => element.EnumerateArray().Select(ConvertJsonValue).ToList(), _ => string.Empty, }; }