Skip to content

Commit

Permalink
13309375: Improve the tests by mocking LiveModel when test mode is (A…
Browse files Browse the repository at this point in the history
…zure#14)

* 13309375: Improve the tests by mocking LiveModel when test mode is
	  Playback but using real LiveModel when test mode is Live

* Change some public classes to private

* Address those comments in the main PR

* Update Microsoft.RL version

* Rename some properties

* Update Microsoft.RL version
  • Loading branch information
johnhuang01 authored Feb 15, 2022
1 parent fc8a166 commit 356fcbc
Show file tree
Hide file tree
Showing 27 changed files with 1,499 additions and 917 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

<ItemGroup>
<PackageReference Include="Azure.Core" />
<PackageReference Include="Microsoft.RL" VersionOverride="1.0.18530001-INTERNAL" />
<PackageReference Include="Microsoft.RL" VersionOverride="1.0.18710001-dev" />
<PackageReference Include="System.Text.Json" VersionOverride="6.0.1" />
</ItemGroup>

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@
using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Usage", "AZC0016:Invalid ServiceVersion member name.", Justification = "Generated code: https://github.com/Azure/autorest.csharp/issues/1524", Scope = "type", Target = "~T:Azure.AI.Personalizer.PersonalizerClientOptions.ServiceVersion")]
[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "<Pending>", Scope = "member", Target = "~P:Azure.AI.Personalizer.DecisionContextDocument.SlotJson")]
[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "<Pending>", Scope = "member", Target = "~P:Azure.AI.Personalizer.PersonalizerSlotOptions.Features")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Rl.Net;

namespace Azure.AI.Personalizer
{
/// <summary> The Wrapper for Rl.Net.ActionProbability </summary>
public class ActionProbabilityWrapper
{
private readonly ActionProbability _actionProbability;

/// <summary> The probability </summary>
public virtual float Probability { get { return _actionProbability.Probability; } }

/// <summary> The action index </summary>
public virtual long ActionIndex { get { return _actionProbability.ActionIndex; } }

/// <summary> Initializes a new instance of ActionProbabilityWrapper. </summary>
public ActionProbabilityWrapper()
{
}

/// <summary> Initializes a new instance of ActionProbabilityWrapper. </summary>
/// <param name="actionProbability"> An action probability </param>
public ActionProbabilityWrapper(ActionProbability actionProbability)
{
_actionProbability = actionProbability;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ public DecisionContext(PersonalizerRankMultiSlotOptions rankRequest, Dictionary<
List<string> actionFeatures = action.Features.Select(f => JsonSerializer.Serialize(f)).ToList();

return new DecisionContextDocument(action.Id, actionFeatures, null, null);
}).ToArray();
}).ToList();
this.Slots = rankRequest.Slots?
.Select(
slot => new DecisionContextDocument(null, null, slot.Id, serializeFeatures(slotIdToFeatures[slot.Id]))
).ToArray();
).ToList();
}

/// <summary> Properties from url </summary>
Expand All @@ -59,12 +59,12 @@ public DecisionContext(PersonalizerRankMultiSlotOptions rankRequest, Dictionary<

/// <summary> Properties of documents </summary>
[JsonPropertyName("_multi")]
public DecisionContextDocument[] Documents { get; set; }
public IList<DecisionContextDocument> Documents { get; }

/// <summary> Properties of slots </summary>
[JsonPropertyName("_slots")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DecisionContextDocument[] Slots { get; set; }
public IList<DecisionContextDocument> Slots { get; }

private static List<string> serializeFeatures(IList<object> features)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,76 +11,52 @@ public class DecisionContextDocument
{
/// <summary> Initializes a new instance of DecisionContextDocument. </summary>
/// <param name="id"> Id of the decision context document </param>
/// <param name="json"> The json features </param>
/// <param name="actionFeatureJsons"> The json list of action features </param>
/// <param name="slotId"> The slot Id </param>
/// <param name="slotJson"> The slot json features </param>
public DecisionContextDocument(string id, List<string> json, string slotId, List<string> slotJson)
/// <param name="slotFeatureJsons"> The json list of slot features </param>
public DecisionContextDocument(string id, List<string> actionFeatureJsons, string slotId, List<string> slotFeatureJsons)
{
ID = id;
JSON = json;
Id = id;
ActionFeatureJsons = actionFeatureJsons;
SlotId = slotId;
SlotJson = slotJson;
SlotFeatureJsons = slotFeatureJsons;
}

/// <summary>
/// Supply _tag for online evaluation
/// </summary>
[JsonPropertyName("_tag")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string ID
{
get { return this?.Marginal?.ID; }
set
{
this.Marginal = value == null ? null : new DecisionContextDocumentId
{
ID = value
};
}
}

/// <summary>
/// Provide feature for marginal feature based on document id.
/// </summary>
[JsonPropertyName("i")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DecisionContextDocumentId Marginal { get; set; }

/// <summary>
/// Provide source set feature.
/// </summary>
[JsonPropertyName("s")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DecisionContextDocumentSource Source { get; set; }
public string Id { get; }

/// <summary>
/// Generic json features.
/// A list of generic action feature jsons.
/// </summary>
[JsonPropertyName("j")]
[JsonConverter(typeof(JsonRawStringListConverter))]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<string> JSON { get; }
public List<string> ActionFeatureJsons { get; }

/// <summary>
/// Keep as float[] arrays to improve marshalling speed.
/// </summary>
[JsonPropertyName("f")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, float[]> FloatFeatures { get; }
public Dictionary<string, float[]> Features { get; }

/// <summary>
/// Slot ID.
/// </summary>
[JsonPropertyName("_id")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string SlotId { get; set; }
public string SlotId { get; }

/// <summary>
/// Generic slot json features.
/// A list of generic slot feature jsons.
/// </summary>
[JsonPropertyName("sj")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonConverter(typeof(JsonRawStringListConverter))]
public List<string> SlotJson { get; set; }
public List<string> SlotFeatureJsons { get; }
}
}

This file was deleted.

This file was deleted.

30 changes: 30 additions & 0 deletions sdk/personalizer/Azure.AI.Personalizer/src/Models/ILiveModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Rl.Net;
using System;

namespace Azure.AI.Personalizer
{
/// <summary> An interface for Rl.Net.LiveModel </summary>
public interface ILiveModel
{
/// <summary> Init LiveModel </summary>
void Init();

/// <summary> Wrapper method of ChooseRank </summary>
RankingResponseWrapper ChooseRank(string eventId, string contextJson, ActionFlags flags);

/// <summary> Wrapper method of RequestMultiSlotDecisionDetailed </summary>
MultiSlotResponseDetailedWrapper RequestMultiSlotDecisionDetailed(string eventId, string contextJson, ActionFlags flags, int[] baselineActions);

/// <summary> Wrapper method of QueueOutcomeEvent </summary>
void QueueOutcomeEvent(string eventId, float outcome);

/// <summary> Wrapper method of RequestMultiSlotDecisionDetailed </summary>
void QueueOutcomeEvent(string eventId, string slotId, float outcome);

/// <summary> Wrapper method of QueueActionTakenEvent </summary>
void QueueActionTakenEvent(string eventId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Rl.Net;
using System;

namespace Azure.AI.Personalizer
{
/// <summary> An adapter class of Rl.Net.LiveModel </summary>
public class LiveModelAdapter : ILiveModel
{
private readonly LiveModel liveModel;

/// <summary> Initializes a new instance of LiveModelAdapter. </summary>
public LiveModelAdapter(LiveModel liveModel)
{
this.liveModel = liveModel ?? throw new ArgumentNullException(nameof(liveModel));
}

/// <summary> Init LiveModel </summary>
public void Init()
{
liveModel.Init();
}

/// <summary> Wrapper method of ChooseRank </summary>
public RankingResponseWrapper ChooseRank(string eventId, string contextJson, ActionFlags flags)
{
RankingResponse rankingResponse = liveModel.ChooseRank(eventId, contextJson, flags);
RankingResponseWrapper rankingResponseWrapper = rankingResponse == null ? null : new RankingResponseWrapper(rankingResponse);

return rankingResponseWrapper;
}

/// <summary> Wrapper method of RequestMultiSlotDecisionDetailed </summary>
public MultiSlotResponseDetailedWrapper RequestMultiSlotDecisionDetailed(string eventId, string contextJson, ActionFlags flags, int[] baselineActions)
{
MultiSlotResponseDetailed multiSlotResponse = liveModel.RequestMultiSlotDecisionDetailed(eventId, contextJson, flags, baselineActions);
MultiSlotResponseDetailedWrapper multiSlotResponseDetailedWrapper = multiSlotResponse == null ? null : new MultiSlotResponseDetailedWrapper(multiSlotResponse);
return multiSlotResponseDetailedWrapper;
}

/// <summary> Wrapper method of QueueOutcomeEvent </summary>
public void QueueOutcomeEvent(string eventId, float outcome)
{
liveModel.QueueOutcomeEvent(eventId, outcome);
}

/// <summary> Wrapper method of RequestMultiSlotDecisionDetailed </summary>
public void QueueOutcomeEvent(string eventId, string slotId, float outcome)
{
liveModel.QueueOutcomeEvent(eventId, slotId, outcome);
}

/// <summary> Wrapper method of QueueActionTakenEvent </summary>
public void QueueActionTakenEvent(string eventId)
{
liveModel.QueueActionTakenEvent(eventId);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Rl.Net;
using System;
using System.Collections;
using System.Collections.Generic;

namespace Azure.AI.Personalizer
{
/// <summary> The Wrapper for Rl.Net.MultiSlotResponseDetailed </summary>
public class MultiSlotResponseDetailedWrapper : IEnumerable<SlotRankingResponseWrapper>
{
private readonly MultiSlotResponseDetailed _multiSlotResponse;

/// <summary> Initializes a new instance of ActionProbabilityWrapper. </summary>
public MultiSlotResponseDetailedWrapper()
{
}

/// <summary> Initializes a new instance of ActionProbabilityWrapper. </summary>
public MultiSlotResponseDetailedWrapper(MultiSlotResponseDetailed multiSlotResponse)
{
_multiSlotResponse = multiSlotResponse ?? throw new ArgumentNullException(nameof(multiSlotResponse));
}

/// <summary> Get the enumerator </summary>
public virtual IEnumerator<SlotRankingResponseWrapper> GetEnumerator()
{
var enu = _multiSlotResponse.GetEnumerator();
while (enu.MoveNext())
{
yield return new SlotRankingResponseWrapper(enu.Current);
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Loading

0 comments on commit 356fcbc

Please sign in to comment.