private static Parameters extractParameters(Class<?> clazz) throws Exception {
		Parameters parameters = new Parameters("object", new HashMap<>(), new ArrayList<>());
		for (Field field : clazz.getDeclaredFields()) {
			Parameter functionParamAnnotation = field.getAnnotation(Parameter.class);
			if (functionParamAnnotation != null) {
				String fieldName = functionParamAnnotation.name();
				String fieldType = getJsonSchemaType(field.getType());
				String fieldDescription = functionParamAnnotation.value();
				if (fieldName.isEmpty()) {
					fieldName = field.getName();
				}
				if (fieldType.equals("array")) {
					Class<?> actualClazz = parseArrayItemClass(field.getGenericType());
					parameters.getProperties()
						.put(fieldName, new Parameters.JsonSchemaProperty(fieldName, "array", fieldDescription,
								new Parameters.JsonArrayItems(getJsonSchemaType(actualClazz), null)));
				} //
				else if (fieldType.equals("object")) {
					throw new Exception("Object type not supported: " + clazz.getName() + "." + field.getName());
				} //
				else {
					parameters.getProperties()
						.put(fieldName, new Parameters.JsonSchemaProperty(fieldName, fieldType, fieldDescription));
				}
				if (functionParamAnnotation.required()) {
					parameters.getRequired().add(fieldName);
				} //
				else {
					for (Annotation annotation : field.getAnnotations()) {
						final String annotationName = annotation.annotationType().getName().toLowerCase();
						if (annotationName.endsWith("nonnull")) {
							parameters.getRequired().add(fieldName);
							break;
						}
					}
				}
			}
		}
		return parameters;
	}
Extract GPT functions from class (and all parent classes/interfaces) by scanning
methods with {@code @GPTFunction}.
@param clazz the Java class whose hierarchy we need to search
@return all functions annotated with
{@code @GPTFunction the @GPTFunction annotation}
src/main/java/org/mvnsearch/chatgpt/model/function/GPTFunctionUtils.java