Skip to content
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

Refactor DanceAiClient code #54851

Merged
merged 11 commits into from
Nov 15, 2023
Merged

Conversation

fisher-alice
Copy link
Contributor

@fisher-alice fisher-alice commented Nov 13, 2023

This PR updates DanceAiClient.ts for easier readability; there is no change in functionality.
I replaced lists with maps, renamed variables/functions and added/updated comments. In particular, I updated comments so that recent changes are reflected, e.g., using Ada instead of Spacy model values and retrieving the top 3 or bottom 3 options based on ChooseEffectsQuality.

Links

Testing story

Deployment strategy

Follow-up work

Privacy

Security

Caching

PR Checklist:

  • Tests provide adequate coverage
  • Privacy and Security impacts have been assessed
  • Code is well-commented
  • New features are translatable or updates will not break translations
  • Relevant documentation has been added or updated
  • User impact is well-understood and desirable
  • Pull Request is labeled appropriately
  • Follow-up work items (including potential tech debt) are tracked and linked

@fisher-alice fisher-alice changed the title refactor code Refactor DanceAiClient code Nov 13, 2023
Comment on lines 54 to 60
const outputWeightsForSelectedEmojis: {[key: string]: number[]} = {};
for (const output in cachedWeightsMappings) {
outputWeightsForSelectedEmojis[output] = calculateOutputWeightsVector(
selectedEmojis,
cachedWeightsMappings[output]
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not blocking at all, but I'd tend to do something like this in a single statement with a reduce:

const outputWeightsForSelectedEmojis: {[key: string]: number[]} =
  Object.entries(cachedWeightsMappings).reduce( (bucket, [key, cachedMapping]) => (
    { ...bucket, [key] : calculateOutputWeightsVector(selectedEmojis, cachedMapping) }
  ), {} )

(not tested, so there may be typos)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to keep things as easy to understand for future readers not familiar with context so I think I may keep as is for that reason.

quality === ChooseEffectsQuality.GOOD
? options.slice(0, numRandomOptions)
: options.slice(-numRandomOptions);
allOutputOptions[output] = topOrBottomOptions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above about doing this in a reduce vs the external define + for/in.

const selectedOutputOption =
outputOptions[Math.floor(Math.random() * outputOptions.length)];
chosenEffects[output as keyof GeneratedEffect] = selectedOutputOption[1];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and again, could be a reduce. But doesn't have to be. 😄

Copy link
Contributor

@thomasoniii thomasoniii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple of non-blocking stylistic suggestions about using a reduce instead of a for/in, but definitely not blocking.

otherwise, lgtm 🚀

@fisher-alice fisher-alice marked this pull request as ready for review November 13, 2023 16:45
@fisher-alice fisher-alice requested a review from a team November 13, 2023 16:45
Copy link
Contributor

@sanchitmalhotra126 sanchitmalhotra126 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great changes - thanks for doing this! Just had a few comments for further refactoring


// Sort and slice top scoring options, mapped to their output identifiers (e.g. [[0.25, 'squiggles'], ...])
// Obtain final output summed weights based on set of three selected emoji inputs
const cachedWeightsMappings: {[key: string]: CachedWeightsMapping} = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: for extra type safety, you could even make this {[key in FieldKey]: CachedWeightsMapping}


// Sort and slice top scoring options, mapped to their output identifiers (e.g. [[0.25, 'squiggles'], ...])
// Obtain final output summed weights based on set of three selected emoji inputs
const cachedWeightsMappings: {[key: string]: CachedWeightsMapping} = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also minor - could this be declared outside of this function (alongside CachedPalettes, etc) since it's always the same for every function invocation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! And removed the individual mappings variables since no longer needed!

Comment on lines +121 to +122
// selectedEmojiAssociations is an array of 3 subarrays. Each subarray contains
// the weights ranging from [0, 1] for the selected emojis for a particular output type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't have to, but if we want to get super strict about this, we can enforce these length requirements with TS directly - something like type EmojiAssociations = [number[], number[], number[]]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried [number, number, number] but got back the error:
'Type 'number[]' is not assignable to type '[number, number, number]'.
Target requires 3 element(s) but source may have fewer.'
I tried changing type of param emojis to [string, string, string] but error still persisted for some reason. So changed back return type back to number[].

const allOutputOptions: {[key: string]: [number, string][]} = {};
for (const output in outputSummedWeightsForSelectedEmojis) {
const weightVector = outputSummedWeightsForSelectedEmojis[output];
const options = obtainOptions(weightVector, cachedWeightsMappings[output]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're here - would it make sense to rename this function to something like get/obtainSortedOptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to getSortedOptions.

};

// Select a random option for each output type from the top or bottom scoring options.
for (const output in allOutputOptions) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General comment about the whole function: If I'm reading this correctly, it looks like we have three for loops that iterate over the same options each time. We're also accessing cachedWeightsMappings[output] a couple different times. Could we organize this with just one loop so we just do the full pass for each output type once? Something like

for (const field of [FieldKey.BACKGROUND_EFFECT, FieldKey.FOREGROUND_EFFECT, ...]) {
  const mapping = cachedWeightsMappings[field];
  const weightVector = calculateOutputSummedWeights(emojis, mapping);
  const options = obtainOptions(weightVector, mapping);
  // ... calculate top options, randomly select, etc
  chosenEffects[field] = effect;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this idea. Will do.

Copy link
Contributor

@sanchitmalhotra126 sanchitmalhotra126 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment on lines 45 to 49
for (const field of [
FieldKey.BACKGROUND_EFFECT,
FieldKey.FOREGROUND_EFFECT,
FieldKey.BACKGROUND_PALETTE,
]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah I guess this could also just be for (const field of Object.keys(chosenEffects) since that's already been declared

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to for (const field of Object.keys(chosenEffects) as FieldKey[]) {
thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh interesting that you need to cast with Object.keys - as an alternative, I think you could also use for (const field of Object.values(FieldKey) and I think that shouldn't require a cast (just tried manually). If you prefer, you could also use that below in the helper function that iterates through the same keys.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Just pushed change.

@fisher-alice fisher-alice merged commit b9f0293 into staging Nov 15, 2023
2 checks passed
@fisher-alice fisher-alice deleted the alice/update-ai-model-client-comments branch November 15, 2023 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants