davsclaus commented on code in PR #26684:
URL: https://github.com/apache/camel/pull/26684#discussion_r4062433406


##########
components/camel-ai/camel-jev/src/main/java/org/apache/camel/component/jev/JevConfiguration.java:
##########
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jev;
+
+import java.net.URI;
+
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.util.ObjectHelper;
+
+@UriParams
+public class JevConfiguration implements Cloneable {
+    @UriParam(label = "security")
+    @Metadata(required = true, secret = true)
+    private String apiKey;
+    @UriParam(defaultValue = "https://api.typesafe.ai";)
+    private String baseUrl = "https://api.typesafe.ai";;
+    @UriParam(defaultValue = "jev-latest")
+    private String model = "jev-latest";
+    @UriParam(defaultValue = "30000")
+    private long requestTimeout = 30000;
+
+    @UriParam
+    private String questions;
+    @UriParam(defaultValue = "${body}")
+    private String state = "${body}";

Review Comment:
   This is what breaks the `PR doc validation` job: the options tables render 
`${body}` and AsciiDoc reads `{body}` as an attribute reference ("skipping 
reference to missing attribute: body", twice - component and endpoint tables). 
Other components handle this by not declaring an attribute-like default and 
describing the behaviour instead:
   
   ```suggestion
       @UriParam
       private String state = "${body}";
   ```
   
   and in the setter Javadoc: "The Simple expression selecting state for 
configured questions. If not set, the message body is used." Then regenerate 
the module and the catalog/DSL mirrors.



##########
core/camel-core-model/src/main/java/org/apache/camel/model/language/JevExpression.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.model.language;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlTransient;
+
+import org.apache.camel.spi.Metadata;
+
+/** Evaluates a Noul question using a configured Jev endpoint. */
+@Metadata(firstVersion = "4.23.0", label = "language,ai", title = "Jev",
+          description = "Evaluates a Noul question using a configured Jev 
endpoint")
+@XmlRootElement(name = "jev")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class JevExpression extends ExpressionDefinition {

Review Comment:
   Per the review body: please move the language (this class, the 
XSD/YAML-schema/EIP-metadata regen, 
`ModelParser`/`ModelWriter`/`YamlModelWriter`, the YAML deserializers and 
`JevLanguage`) out of this PR so the component can land on its own. A language 
that performs a network call is a design change for Camel's DSL and needs its 
own discussion.



##########
components/camel-ai/camel-jev/src/main/java/org/apache/camel/component/jev/JevPredicate.java:
##########
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jev;
+
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.util.json.JsonObject;
+
+/**
+ * A synchronous Noul predicate. Each invocation submits freshly selected 
state, preserves the message body and stores
+ * the complete response in {@link #RESULT}. The supplied state expression 
must be thread-safe.
+ */
+public final class JevPredicate implements Predicate {
+    public static final String RESULT = "CamelJevResult";
+
+    public enum UncertaintyPolicy {
+        NonMatch,
+        Fail
+    }
+
+    private final String endpointUri;
+    private final Expression state;
+    private final String question;
+    private final String questionName;
+    private final double threshold;
+    private final double uncertainty;
+    private final UncertaintyPolicy uncertaintyPolicy;
+
+    public JevPredicate(String endpointUri, Expression state, String 
instructions, double threshold) {
+        this(endpointUri, state, Map.of("type", "noul", "instructions", 
instructions), threshold);
+    }
+
+    public JevPredicate(String endpointUri, Expression state, Map<String, 
Object> question, double threshold) {
+        this(endpointUri, state, question, threshold, 0, 
UncertaintyPolicy.NonMatch);
+    }
+
+    /**
+     * @param endpointUri       the configured Jev endpoint to share with 
producers and other predicates
+     * @param state             selects only the exchange data to submit
+     * @param question          the Noul proposition
+     * @param threshold         a probability at or above this value matches, 
outside the uncertainty band
+     * @param uncertainty       half-width of the inclusive band around 
threshold; zero disables the band
+     * @param uncertaintyPolicy whether uncertainty yields a non-match or an 
exception
+     */
+    public JevPredicate(String endpointUri, Expression state, Map<String, 
Object> question,
+                        double threshold, double uncertainty, 
UncertaintyPolicy uncertaintyPolicy) {
+        this(endpointUri, state, "predicate", question, threshold, 
uncertainty, uncertaintyPolicy);
+    }
+
+    JevPredicate(String endpointUri, Expression state, String questionName, 
Map<String, Object> question,
+                 double threshold, double uncertainty, UncertaintyPolicy 
uncertaintyPolicy) {
+        this.questionName = Objects.requireNonNull(questionName, 
"questionName");
+        this.endpointUri = Objects.requireNonNull(endpointUri, "endpointUri");
+        this.state = Objects.requireNonNull(state, "state");
+        this.question = JevJson.noulQuestion(Objects.requireNonNull(question, 
"question"));
+        this.uncertaintyPolicy = Objects.requireNonNull(uncertaintyPolicy, 
"uncertaintyPolicy");
+        if (!Double.isFinite(threshold) || threshold < 0 || threshold > 1
+                || !Double.isFinite(uncertainty) || uncertainty < 0
+                || threshold - uncertainty < 0 || threshold + uncertainty > 1) 
{
+            throw new IllegalArgumentException("The threshold and its 
uncertainty band must be within [0,1]");
+        }
+        this.threshold = threshold;
+        this.uncertainty = uncertainty;
+    }
+
+    @Override
+    public void init(CamelContext context) {
+        state.init(context);
+        // Register the endpoint even when it is used only by a predicate, so 
Camel owns its lifecycle.
+        context.getEndpoint(endpointUri, JevEndpoint.class);
+    }
+
+    @Override
+    public boolean matches(Exchange exchange) {
+        exchange.removeProperty(RESULT);
+        try {
+            JevEndpoint endpoint = 
exchange.getContext().getEndpoint(endpointUri, JevEndpoint.class);

Review Comment:
   `init()` already resolves the endpoint; resolving it again (plus 
`startService`) on every `matches()` is unnecessary work on the routing thread. 
Consider keeping the `JevEndpoint` in a field set in `init()`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to