-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Client configuration #4
Changes from 13 commits
c586920
43967d3
1e400a8
8e1be98
7ec50ec
0d83604
7bef96f
db8c651
d6df6b5
70c9738
ebbbdad
9856a35
4255840
86532d3
8156ddb
c37c4d3
6b75695
1f0a161
59e364e
92f6ba3
2c7e79c
23d1c93
a914445
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Text.Json; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Azure.Core; | ||
using Azure.Core.Pipeline; | ||
|
||
namespace Azure.AI.Personalizer.Models | ||
{ | ||
internal class ClientConfigurationRestClient | ||
{ | ||
private string endpoint; | ||
private ClientDiagnostics _clientDiagnostics; | ||
private HttpPipeline _pipeline; | ||
|
||
/// <summary> Initializes a new instance of ClientConfigurationRestClient. </summary> | ||
/// <param name="clientDiagnostics"> The handler for diagnostic messaging in the client. </param> | ||
/// <param name="pipeline"> The HTTP pipeline for sending and receiving REST requests and responses. </param> | ||
/// <param name="endpoint"> Supported Cognitive Services endpoint. </param> | ||
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> is null. </exception> | ||
public ClientConfigurationRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string endpoint) | ||
{ | ||
this.endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); | ||
_clientDiagnostics = clientDiagnostics; | ||
_pipeline = pipeline; | ||
} | ||
internal HttpMessage CreatePostRequest() | ||
{ | ||
var message = _pipeline.CreateMessage(); | ||
var request = message.Request; | ||
request.Method = RequestMethod.Post; | ||
var uri = new RawRequestUriBuilder(); | ||
uri.AppendRaw(endpoint, false); | ||
uri.AppendRaw("/personalizer/v1.1-preview.1", false); | ||
uri.AppendPath("/configurations/client", false); | ||
request.Uri = uri; | ||
request.Headers.Add("Accept", "application/json"); | ||
return message; | ||
} | ||
|
||
/// <summary> Get the Personalizer service configuration. </summary> | ||
/// <param name="cancellationToken"> The cancellation token to use. </param> | ||
public async Task<Response<PersonalizerClientProperties>> PostAsync(CancellationToken cancellationToken = default) | ||
{ | ||
using var message = CreatePostRequest(); | ||
await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); | ||
switch (message.Response.Status) | ||
{ | ||
case 200: | ||
{ | ||
PersonalizerClientProperties value = default; | ||
using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); | ||
value = PersonalizerClientProperties.DeserializePersonalizerServiceProperties(document.RootElement); | ||
return Response.FromValue(value, message.Response); | ||
} | ||
default: | ||
throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); | ||
} | ||
} | ||
|
||
/// <summary> Get the Personalizer service configuration. </summary> | ||
/// <param name="cancellationToken"> The cancellation token to use. </param> | ||
public Response<PersonalizerClientProperties> Post(CancellationToken cancellationToken = default) | ||
{ | ||
using var message = CreatePostRequest(); | ||
_pipeline.Send(message, cancellationToken); | ||
switch (message.Response.Status) | ||
{ | ||
case 200: | ||
{ | ||
PersonalizerClientProperties value = default; | ||
using var document = JsonDocument.Parse(message.Response.ContentStream); | ||
value = PersonalizerClientProperties.DeserializePersonalizerServiceProperties(document.RootElement); | ||
return Response.FromValue(value, message.Response); | ||
} | ||
default: | ||
throw _clientDiagnostics.CreateRequestFailedException(message.Response); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Azure.Core; | ||
|
@@ -22,6 +23,9 @@ public class PersonalizerClient | |
internal MultiSlotRestClient MultiSlotRestClient { get; set; } | ||
internal MultiSlotEventsRestClient MultiSlotEventsRestClient { get; set; } | ||
|
||
internal Models.ClientConfigurationRestClient ClientConfigurationRestClient { get; set; } | ||
internal Lazy<Models.PersonalizerClientProperties> result { get; set; } | ||
|
||
/// <summary> Initializes a new instance of Personalizer Client for mocking. </summary> | ||
protected PersonalizerClient() | ||
{ | ||
|
@@ -51,6 +55,7 @@ public PersonalizerClient(Uri endpoint, TokenCredential credential, Personalizer | |
EventsRestClient = new EventsRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
MultiSlotRestClient = new MultiSlotRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
MultiSlotEventsRestClient = new MultiSlotEventsRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
ClientConfigurationRestClient = new Models.ClientConfigurationRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
} | ||
|
||
/// <summary> Initializes a new instance of PersonalizerClient. </summary> | ||
|
@@ -62,6 +67,9 @@ public PersonalizerClient(Uri endpoint, TokenCredential credential, bool isLocal | |
this(endpoint, credential, options) | ||
{ | ||
_isLocalInference = isLocalInference; | ||
LiveModel liveModel = new LiveModel(configuration); | ||
liveModel.Init(); | ||
_rankProcessor = new RankProcessor(liveModel); | ||
} | ||
|
||
/// <summary> Initializes a new instance of PersonalizerClient. </summary> | ||
|
@@ -92,6 +100,7 @@ public PersonalizerClient(Uri endpoint, AzureKeyCredential credential, Personali | |
EventsRestClient = new EventsRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
MultiSlotRestClient = new MultiSlotRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
MultiSlotEventsRestClient = new MultiSlotEventsRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
ClientConfigurationRestClient = new Models.ClientConfigurationRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
} | ||
|
||
/// <summary> Initializes a new instance of PersonalizerClient. </summary> | ||
|
@@ -103,6 +112,12 @@ public PersonalizerClient(Uri endpoint, AzureKeyCredential credential, bool isLo | |
this(endpoint, credential, options) | ||
{ | ||
_isLocalInference = isLocalInference; | ||
if (isLocalInference) | ||
{ | ||
LiveModel liveModel = new LiveModel(GetClientConfigurationForLiveModel()); | ||
liveModel.Init(); | ||
_rankProcessor = new RankProcessor(liveModel); | ||
} | ||
} | ||
|
||
/// <summary> Initializes a new instance of PersonalizerClient. </summary> | ||
|
@@ -121,6 +136,7 @@ internal PersonalizerClient(ClientDiagnostics clientDiagnostics, HttpPipeline pi | |
EventsRestClient = new EventsRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
MultiSlotRestClient = new MultiSlotRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
MultiSlotEventsRestClient = new MultiSlotEventsRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
ClientConfigurationRestClient = new Models.ClientConfigurationRestClient(_clientDiagnostics, _pipeline, stringEndpoint); | ||
_clientDiagnostics = clientDiagnostics; | ||
_pipeline = pipeline; | ||
} | ||
|
@@ -177,7 +193,14 @@ public virtual Response<PersonalizerRankResult> Rank(PersonalizerRankOptions opt | |
scope.Start(); | ||
try | ||
{ | ||
return RankRestClient.Rank(options, cancellationToken); | ||
if (_isLocalInference) | ||
{ | ||
return _rankProcessor.Rank(options, cancellationToken); | ||
} | ||
else | ||
{ | ||
return RankRestClient.Rank(options, cancellationToken); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
|
@@ -482,5 +505,24 @@ public virtual Response ActivateMultiSlot(string eventId, CancellationToken canc | |
throw; | ||
} | ||
} | ||
|
||
/// <summary> Gets the configuration details for the live model to use </summary> | ||
internal Configuration GetClientConfigurationForLiveModel() | ||
{ | ||
result = new Lazy<Models.PersonalizerClientProperties>(() => ClientConfigurationRestClient.Post()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should have a TTL in case the configuration on the server is updated. Also, I would suggest the Lazy TTL be managed by the caller, not inside this method. In other words, the caller should use Lazy. |
||
Console.WriteLine("InternalId: " + result.Value.ApplicationID + "\nStorageBlobUri: " + result.Value.ModelBlobUri + "\nLearningMode: " + result.Value.LearningMode + "\nExploration Percentage: " + result.Value.InitialExplorationEpsilon + "\ninitialCommandline: " + result.Value.InitialCommandLine); | ||
|
||
Configuration config = new Configuration(); | ||
// configure the personalizer loop | ||
config["appid"] = result.Value.ApplicationID; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of call |
||
|
||
Tparuchuri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// set up the model | ||
config["model.source"] = result.Value.ModelBlobUri; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be "model.blob.uri" |
||
config["model.vw.initial_command_line"] = result.Value.InitialCommandLine; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be "vw.commandline" |
||
config["initial_exploration.epsilon"] = Convert.ToString(result.Value.InitialExplorationEpsilon, CultureInfo.InvariantCulture); | ||
config["rank.learning.mode"] = Convert.ToString(result.Value.LearningMode, CultureInfo.InvariantCulture); | ||
//return the config model | ||
return config; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Text.Json; | ||
using Azure.Core; | ||
|
||
namespace Azure.AI.Personalizer.Models | ||
{ | ||
internal partial class PersonalizerClientProperties | ||
{ | ||
internal static PersonalizerClientProperties DeserializePersonalizerServiceProperties(JsonElement element) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain why we need a custom deserializer instead of using |
||
{ | ||
string applicationID = default; | ||
string modelBlobUri = default; | ||
float initialExplorationEpsilon = default; | ||
PersonalizerLearningMode learningMode = default; | ||
string initialCommandLine = default; | ||
foreach (var property in element.EnumerateObject()) | ||
{ | ||
if (property.NameEquals("applicationID")) | ||
{ | ||
applicationID = property.Value.GetString(); | ||
continue; | ||
} | ||
if (property.NameEquals("modelBlobUri")) | ||
{ | ||
modelBlobUri = property.Value.GetString(); | ||
continue; | ||
} | ||
if (property.NameEquals("initialExplorationEpsilon")) | ||
{ | ||
initialExplorationEpsilon = property.Value.GetSingle(); | ||
continue; | ||
} | ||
if (property.NameEquals("learningMode")) | ||
{ | ||
learningMode = new PersonalizerLearningMode(property.Value.GetString()); | ||
continue; | ||
} | ||
if (property.NameEquals("initialCommandLine")) | ||
{ | ||
initialCommandLine = property.Value.GetString(); | ||
continue; | ||
} | ||
} | ||
return new PersonalizerClientProperties(applicationID, modelBlobUri, initialExplorationEpsilon, learningMode, initialCommandLine); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace Azure.AI.Personalizer.Models | ||
{ | ||
internal partial class PersonalizerClientProperties | ||
{ | ||
internal PersonalizerClientProperties(string applicationID, string modelBlobUri, float initialExplorationEpsilon, PersonalizerLearningMode learningMode, string initialCommandLine) | ||
{ | ||
ApplicationID = applicationID; | ||
ModelBlobUri = modelBlobUri; | ||
InitialExplorationEpsilon = initialExplorationEpsilon; | ||
LearningMode = learningMode; | ||
InitialCommandLine = initialCommandLine; | ||
} | ||
/// <summary> | ||
/// Unique identifier for this Personalizer instance. | ||
/// </summary> | ||
public string ApplicationID { get; } | ||
|
||
/// <summary> | ||
/// Event hub connection string for sending interactions. | ||
/// </summary> | ||
public string EventHubInteractionConnectionString { get;} | ||
|
||
/// <summary> | ||
/// Event hub connection string for sending observations. | ||
/// </summary> | ||
public string EventHubObservationConnectionString { get; } | ||
|
||
/// <summary> | ||
/// SAS Uri for the inference model. | ||
/// </summary> | ||
public string ModelBlobUri { get; } | ||
|
||
/// <summary> | ||
/// Exploration value used before downloading model in CB. | ||
/// </summary> | ||
public float InitialExplorationEpsilon { get; } | ||
|
||
/// <summary> | ||
/// Learning Mode setting. | ||
/// </summary> | ||
public PersonalizerLearningMode LearningMode { get; } | ||
|
||
/// <summary> | ||
/// Command line used for prediction before downloading model. | ||
/// </summary> | ||
public string InitialCommandLine { get; } | ||
|
||
/// <summary> | ||
/// Version used by reinforcement learning client. | ||
/// </summary> | ||
public int ProtocolVersion { get; } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this class in the generated folder? Rest clients should not be hand written, only extended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As client Post is not part of swagger because of which it's not part of generated. So implemented it outside generated to get client config details