-
Notifications
You must be signed in to change notification settings - Fork 467
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dotAI): Adding fallback mechanism when it comes to send models. (#…
…29748) Including the concepts of AIProxyClient, AIProxiedClient, AIClientStrategy to decouple functionality of handling AI requests from the actual provider implementation. Refs: #29284
- Loading branch information
1 parent
2f3045b
commit d7ab3bd
Showing
25 changed files
with
1,564 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
dotCMS/src/main/java/com/dotcms/ai/client/AIClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.dotcms.ai.client; | ||
|
||
import com.dotcms.ai.domain.AIProvider; | ||
import org.apache.http.client.methods.HttpDelete; | ||
import org.apache.http.client.methods.HttpGet; | ||
import org.apache.http.client.methods.HttpPatch; | ||
import org.apache.http.client.methods.HttpPost; | ||
import org.apache.http.client.methods.HttpPut; | ||
import org.apache.http.client.methods.HttpUriRequest; | ||
|
||
import javax.ws.rs.HttpMethod; | ||
import java.io.OutputStream; | ||
import java.io.Serializable; | ||
|
||
/** | ||
* Interface representing an AI client capable of sending requests to an AI service. | ||
* | ||
* <p> | ||
* This interface defines methods for obtaining the AI provider and sending requests | ||
* to the AI service. Implementations of this interface should handle the specifics | ||
* of interacting with the AI service, including request formatting and response handling. | ||
* </p> | ||
* | ||
* <p> | ||
* The interface also provides a NOOP implementation that throws an | ||
* {@link UnsupportedOperationException} for all operations. | ||
* </p> | ||
* | ||
* @author vico | ||
*/ | ||
public interface AIClient { | ||
|
||
AIClient NOOP = new AIClient() { | ||
@Override | ||
public AIProvider getProvider() { | ||
return AIProvider.NONE; | ||
} | ||
|
||
@Override | ||
public <T extends Serializable> void sendRequest(final AIRequest<T> request, final OutputStream output) { | ||
throwUnsupported(); | ||
} | ||
|
||
private void throwUnsupported() { | ||
throw new UnsupportedOperationException("Noop client does not support sending requests"); | ||
} | ||
}; | ||
|
||
/** | ||
* Resolves the appropriate HTTP method for the given method name and URL. | ||
* | ||
* @param method the HTTP method name (e.g., "GET", "POST", "PUT", "DELETE", "patch") | ||
* @param url the URL to which the request will be sent | ||
* @return the corresponding {@link HttpUriRequest} for the given method and URL | ||
*/ | ||
static HttpUriRequest resolveMethod(final String method, final String url) { | ||
switch(method) { | ||
case HttpMethod.POST: | ||
return new HttpPost(url); | ||
case HttpMethod.PUT: | ||
return new HttpPut(url); | ||
case HttpMethod.DELETE: | ||
return new HttpDelete(url); | ||
case "patch": | ||
return new HttpPatch(url); | ||
case HttpMethod.GET: | ||
default: | ||
return new HttpGet(url); | ||
} | ||
} | ||
|
||
/** | ||
* Validates and casts the given AI request to a {@link JSONObjectAIRequest}. | ||
* | ||
* @param <T> the type of the request payload | ||
* @param request the AI request to be validated and cast | ||
* @return the validated and cast {@link JSONObjectAIRequest} | ||
* @throws UnsupportedOperationException if the request is not an instance of {@link JSONObjectAIRequest} | ||
*/ | ||
static <T extends Serializable> JSONObjectAIRequest useRequestOrThrow(final AIRequest<T> request) { | ||
// When we get rid of JSONObject usage, we can remove this check | ||
if (request instanceof JSONObjectAIRequest) { | ||
return (JSONObjectAIRequest) request; | ||
} | ||
|
||
throw new UnsupportedOperationException("Only JSONObjectAIRequest (JSONObject) is supported"); | ||
} | ||
|
||
/** | ||
* Returns the AI provider associated with this client. | ||
* | ||
* @return the AI provider | ||
*/ | ||
AIProvider getProvider(); | ||
|
||
/** | ||
* Sends the given AI request to the AI service and writes the response to the provided output stream. | ||
* | ||
* @param <T> the type of the request payload | ||
* @param request the AI request to be sent | ||
* @param output the output stream to which the response will be written | ||
* @throws Exception if any error occurs during the request execution | ||
*/ | ||
<T extends Serializable> void sendRequest(AIRequest<T> request, OutputStream output); | ||
|
||
} |
39 changes: 39 additions & 0 deletions
39
dotCMS/src/main/java/com/dotcms/ai/client/AIClientStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.dotcms.ai.client; | ||
|
||
import java.io.OutputStream; | ||
import java.io.Serializable; | ||
|
||
/** | ||
* Interface representing a strategy for handling AI client requests and responses. | ||
* | ||
* <p> | ||
* This interface defines a method for applying a strategy to an AI client request, | ||
* allowing for different handling mechanisms to be implemented. The NOOP strategy | ||
* is provided as a default implementation that performs no operations. | ||
* </p> | ||
* | ||
* <p> | ||
* Implementations of this interface should define how to process the AI request | ||
* and handle the response, potentially writing the response to an output stream. | ||
* </p> | ||
* | ||
* @author vico | ||
*/ | ||
public interface AIClientStrategy { | ||
|
||
AIClientStrategy NOOP = (client, handler, request, output) -> AIResponse.builder().build(); | ||
|
||
/** | ||
* Applies the strategy to the given AI client request and handles the response. | ||
* | ||
* @param client the AI client to which the request is sent | ||
* @param handler the response evaluator to handle the response | ||
* @param request the AI request to be processed | ||
* @param output the output stream to which the response will be written | ||
*/ | ||
void applyStrategy(AIClient client, | ||
AIResponseEvaluator handler, | ||
AIRequest<? extends Serializable> request, | ||
OutputStream output); | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
dotCMS/src/main/java/com/dotcms/ai/client/AIDefaultStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.dotcms.ai.client; | ||
|
||
import java.io.OutputStream; | ||
import java.io.Serializable; | ||
|
||
/** | ||
* Default implementation of the {@link AIClientStrategy} interface. | ||
* | ||
* <p> | ||
* This class provides a default strategy for handling AI client requests by | ||
* directly sending the request using the provided AI client and writing the | ||
* response to the given output stream. | ||
* </p> | ||
* | ||
* <p> | ||
* The default strategy does not perform any additional processing or handling | ||
* of the request or response, delegating the entire operation to the AI client. | ||
* </p> | ||
* | ||
* @author vico | ||
*/ | ||
public class AIDefaultStrategy implements AIClientStrategy { | ||
|
||
@Override | ||
public void applyStrategy(final AIClient client, | ||
final AIResponseEvaluator handler, | ||
final AIRequest<? extends Serializable> request, | ||
final OutputStream output) { | ||
client.sendRequest(request, output); | ||
} | ||
|
||
} |
83 changes: 83 additions & 0 deletions
83
dotCMS/src/main/java/com/dotcms/ai/client/AIProxiedClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.dotcms.ai.client; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.OutputStream; | ||
import java.io.Serializable; | ||
import java.util.Optional; | ||
|
||
/** | ||
* A proxy client for interacting with an AI service using a specified strategy. | ||
* | ||
* <p> | ||
* This class provides a mechanism to send requests to an AI service through a proxied client, | ||
* applying a given strategy for handling the requests and responses. It supports a NOOP implementation | ||
* that performs no operations. | ||
* </p> | ||
* | ||
* <p> | ||
* The class allows for the creation of proxied clients with different strategies and response evaluators, | ||
* enabling flexible handling of AI service interactions. | ||
* </p> | ||
* | ||
* @author vico | ||
*/ | ||
public class AIProxiedClient { | ||
|
||
public static final AIProxiedClient NOOP = new AIProxiedClient(null, AIClientStrategy.NOOP, null); | ||
|
||
private final AIClient client; | ||
private final AIClientStrategy strategy; | ||
private final AIResponseEvaluator responseEvaluator; | ||
|
||
private AIProxiedClient(final AIClient client, | ||
final AIClientStrategy strategy, | ||
final AIResponseEvaluator responseEvaluator) { | ||
this.client = client; | ||
this.strategy = strategy; | ||
this.responseEvaluator = responseEvaluator; | ||
} | ||
|
||
/** | ||
* Creates an AIProxiedClient with the specified client, strategy, and response evaluator. | ||
* | ||
* @param client the AI client to be proxied | ||
* @param strategy the strategy to be applied for handling requests and responses | ||
* @param responseParser the response evaluator to process responses | ||
* @return a new instance of AIProxiedClient | ||
*/ | ||
public static AIProxiedClient of(final AIClient client, | ||
final AIProxyStrategy strategy, | ||
final AIResponseEvaluator responseParser) { | ||
return new AIProxiedClient(client, strategy.getStrategy(), responseParser); | ||
} | ||
|
||
/** | ||
* Creates an AIProxiedClient with the specified client and strategy. | ||
* | ||
* @param client the AI client to be proxied | ||
* @param strategy the strategy to be applied for handling requests and responses | ||
* @return a new instance of AIProxiedClient | ||
*/ | ||
public static AIProxiedClient of(final AIClient client, final AIProxyStrategy strategy) { | ||
return of(client, strategy, null); | ||
} | ||
|
||
/** | ||
* Sends the given AI request to the AI service and writes the response to the provided output stream. | ||
* | ||
* @param <T> the type of the request payload | ||
* @param request the AI request to be sent | ||
* @param output the output stream to which the response will be written | ||
* @return the AI response | ||
*/ | ||
public <T extends Serializable> AIResponse sendToAI(final AIRequest<T> request, final OutputStream output) { | ||
final OutputStream finalOutput = Optional.ofNullable(output).orElseGet(ByteArrayOutputStream::new); | ||
|
||
strategy.applyStrategy(client, responseEvaluator, request, finalOutput); | ||
|
||
return Optional.ofNullable(output) | ||
.map(out -> AIResponse.EMPTY) | ||
.orElseGet(() -> AIResponse.builder().withResponse(finalOutput.toString()).build()); | ||
} | ||
|
||
} |
Oops, something went wrong.